线程池部分源码详解

ThreadPoolExecutor属性定义的解释

    // Integer总共有32位,最右边29位表示工作线程数,最左边3位表示线程池状态,简单来说,3个二进制位可以表示从0至7的8个不同数值
	private static final int COUNT_BITS = Integer.SIZE - 3;
	// 线程池的容量 2^29 - 1 =  536870911即 000-11111111111111111111111111111
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // 此状态表示线程池能接受新任务 111-00000000000000000000000000000,即十进制的-536870912
    private static final int RUNNING    = -1 << COUNT_BITS;
	// 此状态表示不再接受新任务,但可以继续执行队列中的任务 000-00000000000000000000000000000,即十进制的0
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
	// 此状态表示全面拒绝,并中断正在处理的任务 001-00000000000000000000000000000,即十进制的536870912
    private static final int STOP       =  1 << COUNT_BITS;
	// 此状态表示所有任务已经终止 010-00000000000000000000000000000,即十进制的1073741824
    private static final int TIDYING    =  2 << COUNT_BITS;
	// 此状态表示已清理完现场 011-00000000000000000000000000000,即十进制1610612736
    private static final int TERMINATED =  3 << COUNT_BITS;

    // ~CAPACITY = 111-00000000000000000000000000000 进行与运算获取到左边3位的线程状态
    private static int runStateOf(int c)     { return c & ~CAPACITY; }
	// CAPACITY = 000-11111111111111111111111111111 进行与运算获取到右边29位的线程数
    private static int workerCountOf(int c)  { return c & CAPACITY; }
	// 把左边3位和右边29位按或运算,合并成一个值
    private static int ctlOf(int rs, int wc) { return rs | wc; }


	// 因为RUNNING的十进制值比SHUTDOWN小,所以可以通过这个来判断
    private static boolean isRunning(int c) {
        return c < SHUTDOWN;
    }

    /**
     * 执行失败的概率非常低,及时失败再次执行成功的概率也是极高的,类似于自旋锁的原理。
     * 这里的处理逻辑是先+1,创建失败再-1,这是轻量处理并发创建线程的方式。
     * 如果先创建线程,然后进行加减操作的话,代价明显比这样处理要大
     */
    private boolean compareAndIncrementWorkerCount(int expect) {
        return ctl.compareAndSet(expect, expect + 1);
    }

线程池五中状态分别为 RUNNING,SHUTDOWN,STOP,TIDYING,TERMINATED

而按照十进制值从小到大依次排序为:RUNNING<SHUTDOWN<STOP<TIDYING<TERMINATED

ThreadPoolExecutor.execute()方法源码

public void execute(Runnable command) {
    	//任务为空,抛异常
        if (command == null)
            throw new NullPointerException();
    
    	//返回包含线程数和线程池状态的Integer类型数值
        int c = ctl.get();
    
    	//如果工作线程小于核心线程数,创建线程任务并执行
        if (workerCountOf(c) < corePoolSize) {
            //
            if (addWorker(command, true))
                return;
            //如果创建失败,防止外部已经在线程池中加入新任务,重新获取一遍
            c = ctl.get();
        }
    
    	//如果线程池是RUNNING状态且任务加入队列成功
        if (isRunning(c) && workQueue.offer(command)) {
            //防止外部已经在线程池中加入新任务,重新获取一遍,坚持一遍
            int recheck = ctl.get();
            //如果线程池不是RUNNING状态,则将刚加入的任务从队列中移除,并执行拒绝策略
            if (! isRunning(recheck) && remove(command))
                reject(command);
            //如果之前的线程已经被消费完了,新建一个线程
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
  		//核心线程和队列都满了,尝试创建一个新线程
        else if (!addWorker(command, false))
            //创建失败则唤醒拒绝策略
            reject(command);
    }

ThreadPoolExecutor.addWorker()方法源码

    /**
     * 根据当前线程池状态与给定的界限(核心线程数和最大线程数),检查是否可以添加新的任务线程。如果可以则创建并启动任务
     * 创建成功返回true,失败返回false;返回false的两种情况
     *      1.为线程池状态为STOP或可以关闭即不是RUNNING状态
     *      2.线程工厂创建新的任务线程失败
     * @param firstTask 新线程应首先运行的任务
     * @param core 新增线程时的判断指标
     *              true:判断当前 RUNNING 状态的线程是否小于corePoolSize
     *              false:判断当前 RUNNING 状态的线程是否小于maximumPoolSize
     */
private boolean addWorker(Runnable firstTask, boolean core) {
    	//随机定义的一个字符串,使用break retry时让代码跳出循环且不再进入循环,
    	//使用continue retry时,跳出当前循环进入下一次循环
        retry:
        for (;;) {
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            // 1. 当线程池的状态大于SHUTDOWN时,返回false。因为线程池处于关闭状态了,就不能再接受任务了
        	// 2. 当线程池的状态是STOP及之上的状态,firstTask不为空或者任务队列为空,返回false
            if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                   firstTask == null &&
                   ! workQueue.isEmpty()))
                return false;

            for (;;) {
                //获取工作线程数
                int wc = workerCountOf(c);
                // 1. 线程数大于等于理论上的最大数(2^29-1),则直接返回false。(因为超过最大允许线程数会影响左边3位的线程池状态值)
            	// 2. 根据core来决定线程数应该和谁比较。当线程数大于核心线程数或者最大线程数时,直接返回false。
            	// (因为当大于核心线程数时,表示此时任务应该直接添加到队列中(如果队列满了,可能入队失败);当大于最大线程数时,肯定不能再新创建线程了)
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //将当前活动线程数+1
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                //因为线程池状态和工作线程数是随时可变的,所以要经常提取这个最新值,并将其与前面获取到的值比较,
                // 如果相同,说明线程池的状态没有发生变化,继续在内循环中进行循环
            	// 如果不相同,说明在这期间,线程池的状态发生了变化,需要跳到外层循环,然后再重新进行循环
                c = ctl.get();  // Re-read ctl
                if (runStateOf(c) != rs)
                    continue retry;
                // else CAS failed due to workerCount change; retry inner loop
                // 否则CAS由于workerCount更改而失败;重试内部循环
            }
        }

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            // 创建一个新的worker线程
            w = new Worker(firstTask);
            final Thread t = w.thread;
            if (t != null) {
                //在进行ThreadPoolExecutor的敏感操作时,都需要持有锁,避免在添加和自启动线程时被干扰
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    //获取锁时进行重新检查,如果ThreadFactory失败或在获得锁之前关闭,请退回
                    int rs = runStateOf(ctl.get());
                    //如果线程是RUNNING状态或者虽然是关闭状态,但是firstTask是null,就讲worker线程添加到线程池中
                    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();
                }
                if (workerAdded) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

工作线程的核心类实现,Worker源码

        /**
         * 实现Runnable接口,并把本对象作为参数输入给run()方法中的runWorker(this),
   		 * 所以内部属性线程thread在start的时候,即会调用runWorker方法
         */
	private final class Worker
        extends AbstractQueuedSynchronizer
        implements Runnable
    {
        /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
            // 它是AbstractQueuedSynchronizer的方法
            // 在runWorker方法执行之前禁止线程被中断
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

        // 当thread被start()之后,执行runWorker方法
        public void run() {
            runWorker(this);
        }
    }

通过ThreadPoolExecutor的方法创建线程池,能更加明确线程池的运行规则,规避资源耗尽的风险

参考:《码出高效》,《面试官:来!聊聊线程池的实现原理以及使用时的问题》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值