线程池源码分析(二)

一、ThreadPoolExecutor中的核心变量和内部类

1.1 ctl

线程池内部使用ctl来维护线程状态(runState)和线程数量(workerCount),高三位表示线程线程状态(runState),低29位表示线程数量(workerCount)

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

1.2 内部类Worker

Worker是线程池中为了维护线程的状态并维护线程的生命周期而设计的。

这worker类实现了Runnable接口,并持有一个线程和一个初始化任务。

private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        private static final long serialVersionUID = 6138294804551838833L;
    	// worker持有的线程,可以为空
        final Thread thread;
        //初始化任务
        Runnable firstTask;
        
    /*省略*/
        
    }

二、execute()分析

所有的任务调度都由有execute()进行完成的。主要有三部分

  • 判断当前的工作线程数是否小于核心线程数
  • 判断线程池是否为Running状态并且可以加入到缓存队列中
  • 判断是否可用尝试添加一个新的线程

详细分析

public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
    	// 获取ctl值(包括了线程状态和线程数量)
        int c = ctl.get();
    	// workerCountOf(): 根据clt获取线程数量
    	// 判断当前线程数是否小于核心线程数
        if (workerCountOf(c) < corePoolSize) {
            /**
           * addWorker(): 尝试增加核心线程或者非核心线程以执行任务(区分core)
           * @param firstTask 表示线程启动后第一个执行的任务
           * @param core 判断新添加的线程是否应该被视为核心线程(true)还是非核心线程(false)。
           */
            if (addWorker(command, true))
                return;
            // 再次获取值
            c = ctl.get();
        }
    	// 如果当前的线程池还在运行并且加入缓存队列成功
        if (isRunning(c) && workQueue.offer(command)) {
            // 获取clt
            int recheck = ctl.get();
            // 如果线程池状态不是运行状态就从队列移除任务并拒绝执行
            if (! isRunning(recheck) && remove(command))
                reject(command);
            // 如果活跃的线程为空时
            else if (workerCountOf(recheck) == 0)
                // 尝试添加一个非核心线程来检查队列
                addWorker(null, false);
        }
    	//如果不能直接执行也不能入队,尝试添加非核心线程执行任务,失败则拒绝任务 
        else if (!addWorker(command, false))
            reject(command);
    }

其执行流程如下图所示:
转载来自Java线程池实现原理及其在美团业务中的实践

三、addWokret()

addWokert方法只要是负责创建新线程,并启动线程

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            // 获取ctl
            int c = ctl.get();
            // 获取当前线程池的状态
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            // 1、如果当前线程池的状态大于等于SHUTDOWN,则返回false
            // 2、如果当前当前线程池的状态等于SHUTDOWN,并且firstTask为空,缓存队列为空,则返回false
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                // 获取线程中当前活跃的线程数量
                int wc = workerCountOf(c);
                // 检查线程容量
                if (wc >= CAPACITY ||  // 如果达到线程池的最大容量
                    wc >= (core ? corePoolSize : maximumPoolSize))   // 或者达到核心线程池大小(如果`core`为`true`)
                    return false;
                // 通过循环加cas修改ctl的值,增加线程数量
                if (compareAndIncrementWorkerCount(c))
                    // 表示新增成功,跳出循环
                    break retry;
                 // 再次获取ctl的最新值
                c = ctl.get();  // Re-read ctl
                // 判断线程池状态是否一致
                if (runStateOf(c) != rs)
                    // 重新执行循环
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
		// 标识线程是否已经执行
        boolean workerStarted = false;
    	// 标识线程是否加入hashSet(存储线程的容器)
        boolean workerAdded = false;
        Worker w = null;
        try {
            // 创建线程
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());

                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        workers.add(w);
                        // 获取线程池中的线程数量
                        int s = workers.size();
                        if (s > largestPoolSize)
                            // 记录线程池中出现的线程数
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                // 判断是否加入hashSet中
                if (workerAdded) {
                    // 启动线程
                    t.start();
                    // 标识任务已经执行
                    workerStarted = true;
                }
            }
        } finally {
            // 如果线程还没有执行
            if (! workerStarted)
                 //移除工作线程
                addWorkerFailed(w);
        }
        return workerStarted;
    }

其执行流程如下图所示:
图片来源于:https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html
图片来源于:Java线程池实现原理及其在美团业务中的实践

四、参考资料

【1】Java线程池实现原理及其在美团业务中的实践

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值