【源码笔记】ThreadPoolExecutor#execute

/**
 * Executes the given task sometime in the future.  The task
 * may execute in a new thread or in an existing pooled thread.
 *
 * If the task cannot be submitted for execution, either because this
 * executor has been shutdown or because its capacity has been reached,
 * the task is handled by the current {@code RejectedExecutionHandler}.
 *
 * @param command the task to execute
 * @throws RejectedExecutionException at discretion of
 *         {@code RejectedExecutionHandler}, if the task
 *         cannot be accepted for execution
 * @throws NullPointerException if {@code command} is null
 */
// command可以是普通的runnable也可以是futureTask
public void execute(Runnable command) {
    // 非空判断
    if (command == null)
        throw new NullPointerException();
    /*
     * Proceed in 3 steps:
     *
     * 1. If fewer than corePoolSize threads are running, try to
     * start a new thread with the given command as its first
     * task.  The call to addWorker atomically checks runState and
     * workerCount, and so prevents false alarms that would add
     * threads when it shouldn't, by returning false.
     *
     * 2. If a task can be successfully queued, then we still need
     * to double-check whether we should have added a thread
     * (because existing ones died since last checking) or that
     * the pool shut down since entry into this method. So we
     * recheck state and if necessary roll back the enqueuing if
     * stopped, or start a new thread if there are none.
     *
     * 3. If we cannot queue task, then we try to add a new
     * thread.  If it fails, we know we are shut down or saturated
     * and so reject the task.
     */
    // 获取ctl最新值
    // ctl:高3位表示线程池状态;低位表示线程池中线程数量
    int c = ctl.get();
    // workerCountOf获取出ctl表示的线程数量
    // 条件成立:表示当前线程数小于核心线程数 --> 直接创建一个新的worker
    if (workerCountOf(c) < corePoolSize) {
        // addWorker --> 创建线程的过程,会创建worker对象,并且将command作为firstTask
        // core --> true:采用corePoolSize限制;false:采用maximumPoolSize限制
        if (addWorker(command, true))
            // 创建成功后,直接返回
            // addWorker会启动新创建的worker,执行firstTask
            return;
        // 执行到这条语句,说明addWorker失败了。可能的情况:
        //   1. 存在并发,execute有多个线程同时调用。不止一个线程workerCountOf(c) < corePoolSize条件成立,并且向线程池中创建了worker。
        //      这个时候,线程池中的核心线程数已经达到最大值
        //   2. 当前线程池状态发生了改变:当线程池状态不是RUNNING时,addWorker会失败
        //      特殊情况:SHUTDOWN状态下,也有可能创建成功。前提firstTask==null,并且当前queue不为空
        c = ctl.get();
    }

    // 执行到这里,有几种情况?
    //   1. 当前线程数达到corePoolSize
    //   2. addWorker失败

    // 条件成立:说明当前线程池是running状态,则尝试将task放入workQueue中
    if (isRunning(c) && workQueue.offer(command)) {
        // 执行到这里说明offer提交任务成功了

        // 再次获取ctl,保存到recheck中
        int recheck = ctl.get();

        // 如果非running条件成立,则或执行remove
        // 条件1. ! isRunning(recheck)
        //       --> true 说明,提交任务到队列后,线程池状态被外部线程修改了。比如:shutdown()或者shutdownNow()
        //                这种情况,需要把刚提交的任务删除掉
        // 条件2. remove(command)
        //       --> true 提交之后,线程池中的线程还未消费(处理)
        //       --> false 提交之后,在shutdown() shutdownNow()之前,就被线程池中的线程处理了
        if (! isRunning(recheck) && remove(command))
            // 提交之后,线程池状态为非running 且 任务出队成功 --> 拒绝策略
            reject(command);

        // 有几种情况会到这里?
        //   1.当前线程池是running状态 --> 这个概率最大
        //   2.当前线程池是非running状态,但是remove task失败

        // 避免一种情况:当前线程池是running状态,但是线程池中的存活线程数量是0
        // 如果是0的话,会很尴尬 --> 任务没有线程去做了 --> 担保机制:保证线程池在running状态下,最起码有一个线程在工作
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    // 执行到这里,有几种情况?
    //   1.offer失败
    //   2.当前线程池是非running状态

    // 1.offer失败,说明:当前queue满了。
    //     如果当前线程数尚未达到maximumPoolSize --> 创建新的worker直接执行command
    //     如果当前线程数达到maximumPoolSize --> 返回false
    // 2.线程池状态为非running状态。因为command!=null,所以addWorker一定返回false
    else if (!addWorker(command, false))
        reject(command);
}
posted @ 2022-09-22 22:50  daheww  阅读(33)  评论(0编辑  收藏  举报