JBoss 系列九十八:JBoss MSC - 浅析 ServiceContainer

100 篇文章 56 订阅
本文介绍了JBoss MSC中的ServiceContainer接口及其重要组件ServiceTarget和服务注册接口ServiceRegistry。重点关注ContainerExecutor,它是基于ThreadPoolExecutor实现的线程池,详细解释了其核心参数的作用。同时,文章探讨了`synchronized`关键字在ServiceContainer中的应用,阐述了Java的同步机制和monitor概念。
摘要由CSDN通过智能技术生成

ServiceContainer 接口类图

ServiceContainer 接口类图如下所示:


如图:

  • ServiceContainer - ServiceContainer 即是 JBoss MSC 的抽象,它抽象的是一个模块化的容器,它设计用来管理一系列服务
  • ServiceTarget - 提供了添加服务,添加依赖等方法,另外这些添加只有在ServiceBuilder 的 install() 方法后才生效
  • ServiceRegistry - 服务注册接口,可根据服务名获取一个服务,或获取所有服务名列表
另外,ServiceContainer 包含一个工厂类,用来创建 ServiceContainer,工厂类中 create() 方法如下:

public static ServiceContainer create()
public static ServiceContainer create(String name)
public static ServiceContainer create(int coreSize, long keepAliveTime, TimeUnit keepAliveTimeUnit)
public static ServiceContainer create(String name, int coreSize, long keepAliveTime, TimeUnit keepAliveTimeUnit)
public static ServiceContainer create(boolean autoShutdown)
public static ServiceContainer create(String name, boolean autoShutdown)
public static ServiceContainer create(int coreSize, long keepAliveTime, TimeUnit keepAliveTimeUnit, boolean autoShutdown)
public static ServiceContainer create(String name, int coreSize, long keepAliveTime, TimeUnit keepAliveTimeUnit, boolean autoShutdown)

注意,这些create() 方法中的参数是用于实例化ServiceContainer时创建ThreadPoolExecutor。

ContainerExecutor

ServiceContainer 接口的实现类 ServiceContainerImpl 中有一个 ContainerExecutor 属性,其中在实例化ServiceContainerImpl被初始化,ContainerExecutor 实现了 ThreadPoolExecutor 且使用如下构造方法:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)

如上使用一些初始化参数构建 ThreadPoolExecutor:

  • corePoolSize - 线程池中保存的线程数,不管线程是否空闲,当线程数大小小于 corePoolSize 就新建线程,并处理请求
  • maximumPoolSize - 线程池允许的最大线程数
  • keepAliveTime - 当线程池中线程数大于 corePoolSize 时,多余的线程在等待空闲时间 keepAliveTime 后终止
  • unit - keepAliveTime 的时间单位
  • workQueue - Task 被执行之前首先至于此 workQueue,当然 workQueue 只保存实现 Runnable 的 Task,通常被 execute 方法提交
  • threadFactory - 用来创建创建新线程
  • handler - 当队列里累积的 Task 多于 workQueue 最大容量时用来处理新来的 Task
JBoss MSC ContainerExecutor 构造方法如下:

ContainerExecutor(final int corePoolSize, final int maximumPoolSize, final long keepAliveTime, final TimeUnit unit) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
                private final int id = executorSeq.getAndIncrement();
                private final AtomicInteger threadSeq = new AtomicInteger(1);
                public Thread newThread(final Runnable r) {
                    Thread thread = new ServiceThread(r, ServiceContainerImpl.this);
                    thread.setName(String.format("MSC service thread %d-%d", Integer.valueOf(id), Integer.valueOf(threadSeq.getAndIncrement())));
                    thread.setUncaughtExceptionHandler(HANDLER);
                    return thread;
                }
            }, POLICY);
        }

如上,workQueue 没有定义容量限制,工作线程命名规则 MSC service thread %d-%d,所以我们在  JBoss MSC - 简单介绍及一个简单示例 中可以看到线程所谓名字如 MSC service thread 1-1。

JBoss MSC ContainerExecutor 的启动是ServiceBuilder 的 install 方法,使的 ServiceContainerImpl 的 doExecute 方法中执行,此方法完成容器初始化:

    void doExecute(final ArrayList<Runnable> tasks) {
        assert !holdsLock(this);
        if (tasks == null) return;
        final Executor executor = primaryRegistration.getContainer().getExecutor();
        for (Runnable task : tasks) {
            try {
                executor.execute(task);
            } catch (RejectedExecutionException e) {
                task.run();
            }
        }
    }

如 JBoss MSC - 简单介绍及一个简单示例 中的示例,我们只启动一个服务,但是示例执行完成后容器中有8个线程,这是因为我们初始化的 corePoolSize 为 8,当线程数小于 corePoolSize 就新建线程,并处理请求。

synchronized关键字

Java 语言提供了很多种多线程之间通信的机制,但最基本的方式是通过 `monitor` 实现的 `synchronization` 机制。这个机制主要使用关键字是 synchronized,ServiceContainer 中的很多地方使用到该关键字,关于这个同步机制以及 synchronized 关键字我们可总结如下几点:

  1. Java 中每一个对象都关联一个 `monitor`,static申明对应的对象是相应的 Class 对象
  2. Java 通过 synchronized 来获取 `monitor`
  3. Java 中任意线程可锁定一个 `monitor`
  4. Java 中同一线程可对 `monitor` 多次锁定或解锁,但当一个对象的 `monitor` 被锁定,其他线程要获取此 `monitor`  就需要等待

举例说明,如下代码段:

public class Demo {

	public synchronized void foo(){}
	
	public synchronized void zoo() {}
	
	public static synchronized void bar() {}
	
}

假设 Demo 对象被实例化,

  • 如果线程 A 在访问 foo 方法且没有完成,则其他线程不能够访问 zoo 方法 - 因为访问 foo 方法时通过 synchronized 获取了 Demo 对象的 `monitor` ,其他线程要访问 zoo 方法时,同样需要获取 Demo 对象的 `monitor` ,但是由于 foo 方法没有完成,所以 `monitor` 上的锁没有被释放,即访问 zoo 需要等待锁释放
  • 如果线程 A 在访问 foo 方法且没有完成,其他线程可以访问bar方法,因为 static 方法对应的对象是 Class 对象,所以static 方法可以访问
和上面代码段等效的写法如下:

public class Demo {
		
	public void foo(){synchronized(this) {}}
	
	public void zoo() {synchronized(this) {}}
	
	public static void bar() {synchronized(Demo.class) {}}
}

事实上,我们更推荐使用下面的方法,这样更能体现出 Java 中一个对象都关联一个 `monitor`。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值