【源码笔记】ThreadPoolExecutor#getTask

/**
 * Performs blocking or timed wait for a task, depending on
 * current configuration settings, or returns null if this worker
 * must exit because of any of:
 * 1. There are more than maximumPoolSize workers (due to
 *    a call to setMaximumPoolSize).
 * 2. The pool is stopped.
 * 3. The pool is shutdown and the queue is empty.
 * 4. This worker timed out waiting for a task, and timed-out
 *    workers are subject to termination (that is,
 *    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})
 *    both before and after the timed wait, and if the queue is
 *    non-empty, this worker is not the last thread in the pool.
 *
 * @return task, or null if the worker must exit, in which case
 *         workerCount is decremented
 */
// 什么情况下会返回null?
// 1.rs >= STOP
// 2.SHUTDOWN && workQueue.isEmpty()
// 3.线程池中的线程数超过最大限制时,会有一部分线程返回null
//   wc > maximumPoolSize && (wc > 1 || workQueue.isEmpty())
// 4.线程池中的线程数超过corePoolSize时,会有一部分线程返回null
//   (timed && timedOut) && (wc > 1 || workQueue.isEmpty())
private Runnable getTask() {
    // 当前线程获取任务是否超时
    boolean timedOut = false; // Did the last poll() time out?

    // 自旋
    for (;;) {
        // 获取最新ctl的值
        int c = ctl.get();
        // 获取线程池当前运行状态
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        // 条件1.rs >= SHUTDOWN
        //   true --> 当前线程池状态不为running
        // 条件2.(rs >= STOP || workQueue.isEmpty())
        //   条件2.1 rs >= STOP
        //     true --> 当前线程池的状态最低也是stop了,则getTask会失败
        //   条件2.2 workQueue.isEmpty()
        //     前置条件:线程池的状态是SHUTDOWN
        //     true --> queue为空,则getTask会失败
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            // 返回null,runWorker就会将返回值为null的线程执行退出线程池的逻辑
            // worker count减一(CAS+自旋)
            decrementWorkerCount();
            return null;
        }

        // 执行到这里,有两种情况:
        // 1. 线程池状态是RUNNING
        // 2. 线程池状态是SHUTDOWN,且queue不为空
        // 只有这两种情况可以创建线程

        // 获取到worker的数量
        int wc = workerCountOf(c);

        // Are workers subject to culling?
        // 条件:allowCoreThreadTimeOut || wc > corePoolSize
        //   true --> 当前线程池获取线程支持超时机制,queue.poll(xxx,xxx);在获取task超时的情况下,下一次自旋可能就返回null了
        //   false -> 当前线程池获取线程不支持超时机制的。当前线程会使用queue.take()
        // allowCoreThreadTimeOut 是否允许核心线程超时
        // - 若为true,则说明不论那种线程,获取task的时候都要加入超时机制
        // - 若为false,则获取核心线程的任务不允许超时,但是获取非核心线程的任务加入超时机制
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

        // 条件1.(wc > maximumPoolSize || (timed && timedOut))
        //   条件1.1 wc > maximumPoolSize 可能会成立的原因:
        //     外部线程调用了setMaximumPoolSize方法,将线程池最大线程数设置为比初始化的时候要小
        //   条件1.2 timed && timedOut
        //     有超时机制,且上一次循环时,使用poll方式获取任务时,超时了
        // 条件1代表,线程达到了回收的标准,可以被回收。等确实需要回首时再回收
        // 条件2.(wc > 1 || workQueue.isEmpty())
        //   条件2.1 wc > 1
        //     true --> 说明线程池中还有其它线程,当前线程可以直接回收 --> 返回null
        //   条件2.2 workQueue.isEmpty()
        //     前置条件:wc == 1
        //     true --> 说明当前任务队列已经空了,最后一个线程也可以放心退出
        //
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            // 使用CAS的方式让workerCount减一
            // CAS成功的线程返回null
            // CAS失败的线程continue自旋
            //   CAS失败的原因:1.其它线程先减了数量;2.线程池的状态发生了变化
            if (compareAndDecrementWorkerCount(c))
                return null;

            // 再次自旋时,timed可能为false
            // 因为当前线程CAS失败,可能是因为其它线程成功退出导致的
            // 再次自旋时,wc <= corePoolSize --> 即属于不需要回收的范围内了
            continue;
        }

        // 以下为获取任务的逻辑

        try {
            // 获取任务
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();

            // 任务不为null,返回任务
            if (r != null)
                return r;
            // 执行到这里,获取任务超时了(如果不为null,则已经返回了;为null,则说明获取task超时)
            // 下一次自旋的时候,可能就会返回null了
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}
posted @ 2022-09-25 21:19  daheww  阅读(114)  评论(0编辑  收藏  举报