线程池ThreadPoolExecutor源码详解 --- 更新中

线程池ThreadPoolExecutor源码跟踪

execute(Runnable command)

public void execute(Runnable command) {
    // 不允许提交null
    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.
     */
    // 获取工作线程总数,判断如果小于核心线程数,则启动一个核心线程去执行任务,如果大于等于核心线程数,或启动新线程失败,则进入下面的判断
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // todo CachedThreadPoolExecutor在最开始的时候这里的怎么过掉的?
    // 疑问点在于,Cache线程池刚启动时,核心线程数为0,那么上面那个if判断会直接过掉,而它的工作队列是SynchronousQueue,没有工作线程的情况下offer()应该会一直阻塞在那里,这不就陷入了死循环??
    // 如果线程池状态正常,且往工作队列中添加任务成功,则进行二次校验,防止线程池状态在这之间变化
    if (isRunning(c) && workQueue.offer(command)) {
        // 检查线程池状态,如果线程池状态异常,则我们需要移除刚才添加到工作队列中的任务
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            // 线程池状态异常,且移除任务成功,对该任务执行拒绝策略
            reject(command);
        // 反之,如果线程池状态正常,或线程池状态异常,但是移除任务失败,则再判断工作线程数,如果为0,则启动一个新线程
        // 对于前者,状态正常,但是工作线程数为0,那么启动一个新线程很正常
        // 对于后者,线程池状态异常,从工作队列中移除任务失败,但是判断线程池中线程数量为0,此时再启动一个新线程来执行任务,应该是一个无奈之举,毕竟移除任务失败了
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    // 如果线程池状态异常,或线程状态正常,但是往工作队列中添加任务失败,那么启动一个新工作线程来执行直接任务,并在启动失败时执行拒绝策略
    // 对于这两种情况,addWorker()中都会根据线程池状态判断应该返回的结果
    else if (!addWorker(command, false))
        reject(command);

addWorker(Runnable firstTask, boolean core)

private boolean addWorker(Runnable firstTask, boolean core) {
    // 定义一个retry循环
    retry:
    for (;;) {
        // 获取当前线程池状态
        int c = ctl.get();
        int rs = runStateOf(c);
        // 如果线程池状态大于等于SHUTDOWN,且不等于SHUTDOWN时(TIDYING/STOP/TERMINATED),工作队列为空,firstTask不为空,则直接返回false,告知增加worker失败
        // 这里是为了应对execute()方法中的两种情况,一种是线程池状态为SHUTDOWN,但是工作队列中被添加了任务且移除失败,此时没办法必须启动一个新线程把任务执行掉,传入的firstTask为null
        // 第二种情况是线程池状态异常,那么在非SHUTDOWN、且任务不为空、工作队列为空的情况下,直接返回false,告知调用方添加线程失败
        if (rs >= SHUTDOWN &&
                ! (rs == SHUTDOWN &&
                        firstTask == null &&
                        ! workQueue.isEmpty()))
            return false;
        // 该层循环的作用是计算线程数,确认能增加并增加
        for (;;) {
            // 获取当前线程数量
            int wc = workerCountOf(c);
            // CAPACITY是线程池可允许的线程最大数量,如果大于该值,或核心线程/最大线程已达到,则返回false,告知无法新增新线程
            if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            // 采用cas对线程数量进行增加,如果成功即可中断当前retry循环
            if (compareAndIncrementWorkerCount(c))
                break retry;
            // 使用cas增加线程数量失败,判断线程池状态是否和retry循环开始时的线程池状态相同,相同的话则继续retry的内循环,不同的话中断内循环,继续外循环
            c = ctl.get();  // Re-read ctl
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }
    // 到这里说明线程数量workCount已经增加完毕,需要进行真正的创建线程动作了
    // 定义两个布尔值,分别代表新增的线程已启动和已创建
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 包装传入的Runnable,Worker中会存储有一个工作线程Thread,和传入的任务内容Runnable,工作线程会直接调用任务内容的run()
        w = new Worker(firstTask);
        final Thread t = w.thread;
        // 如果线程为空,说明ThreadFactory出问题了,if中的代码也不需要执行
        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());
                // 如果当前线程池状态为RUNNING,或为SHUTDOWN,且firstTask为空,则继续以下的逻辑
                // 线程池状态为SHUTDOWN,且firstTask为空,意味着当前方法只是为了启动一个新的工作线程
                if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                    // 如果线程状态是alive,说明线程的start()已经被调用,抛出线程状态异常
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    // 添加到工作线程集合中
                    workers.add(w);
                    // 判断当前工作线程数量,并赋值该largestPoolSize,该变量的作用是追踪当前线程池的最大线程数量
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    // 更新workerAdded变量,代表工作线程已经被添加到线程池中
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            // 如果工作线程已经被添加到线程池中,那么就启动工作线程中的执行线程,并更新workerStarted为true,代表工作线程已经被启动
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        // 如果因为某些原因工作线程启动失败,会调用addWorkerFailed(),该方法主要做三件事,从线程池中移除这个启动失败的线程,减少线程数量,并调用tryTerminated()方法尝试终止线程池
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

shutdown()

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 校验当前线程是否有关闭线程的权限,并检查当前线程对每个工作线程是否有权限操作
        checkShutdownAccess();
        // 采用cas方法更新线程池状态
        advanceRunState(SHUTDOWN);
        // 中断空闲的工作线程
        interruptIdleWorkers();
        // shutdown的钩子方法,ThreadPoolExecutor没有使用该方法,ScheduledThreadPoolExecutor会使用该方法情况workQueue
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    // 尝试更新线程池状态为TERMINATED
    tryTerminate();
}

shutdownNow()

public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    // 加锁操作
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 校验当前线程是否有关闭线程的权限,并检查当前线程对每个工作线程是否有权限操作
        checkShutdownAccess();
        // 采用cas方法更新线程池状态
        advanceRunState(STOP);
        // 直接中断所有started的且未interrupt的工作线程
        interruptWorkers();
        // 将剩余的任务返回,并清空workQueue
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    // 尝试更新线程池状态为TERMINATED
    tryTerminate();
    return tasks;
}

tryTerminate()

final void tryTerminate() {
    for (;;) {
        // 获取状态
        int c = ctl.get();
        // 判断线程池状态是RUNNING,或线程池状态是TIDYING或TERMINATED,或当前线程池状态为SHUTDOWNS时工作队列不为空
        // 第一种情况线程池无法关闭,第二种情况下线程池会直接调用terminated()方法终止线程,不需要tryTerminate(),第三种情况下需先等待任务队列全部执行完
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        // 如果当前工作线程数不为0,则中断一个空闲的工作线程以传播shutdown信号
        // todo 后半句没懂,传播shutdown信号?做什么?方法中只是单纯的中断了一个工作线程,没有做其它任何事
        // 这里中断的是空闲的工作线程,会导致runWorker()中抛出interrupt异常,然后进入processWorkerExit(),然后再次调用tryTerminate(),
        // 不断循环直到workCount一直为0?这种传播?
        if (workerCountOf(c) != 0) { // Eligible to terminate
            interruptIdleWorkers(ONLY_ONE);
            return;
        }
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            // 设置当前线程池状态为TIDYING
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    // 线程终止方法,在ThreadPoolExecutor只是个空方法
                    terminated();
                } finally {
                    // 线程池已终止,设置线程池状态为TERMINATED,并通过Condition通知所有的awaitTermination()方法
                    ctl.set(ctlOf(TERMINATED, 0));
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}

runWorker(Worker w)

final void runWorker(Worker w) {
    // 获取当前线程
    Thread wt = Thread.currentThread();
    // 获取工作线程内已有的firstTask,并将工作线程的firstTask置空
    Runnable task = w.firstTask;
    w.firstTask = null;
    // 在实际开始执行任务前解锁当前worker,允许在这段时间内中断worker
    w.unlock(); // allow interrupts
    // 用于标记当前线程是否完全中断
    boolean completedAbruptly = true;
    try {
        // 当task不为空或getTask()可以获取到任务时,执行while循环
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
            // 判断线程池状态,如果{线程池状态为STOP后 或 {当前线程中断且线程池已关闭且且线程池状态为STOP后}} 且线程中断后没有再中断,则中断当前线程
            // todo 想知道这些判断都是针对什么情况的...
            if ((
                    runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))
                )
                 && !wt.isInterrupted())
                wt.interrupt();
            try {
                // 执行前置钩子方法
                beforeExecute(wt, task);
                Throwable thrown = null;
                // 直接运行task的run(),然后捕获异常,将Throwable的异常包装成Error,所有异常捕获后赋值给thrown后再抛出,
                // 抛出的部分由uncaughtExceptionHandler处理,thrown用于afterExecute处理
                try {
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    // 执行后置钩子方法
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        // 线程因为某些自身原因终止(一般是被线程池interrupt),需要执行工作线程退出的一些流程,其中会调用tryTerminate终止线程池
        // completedAbruptly:代表线程是否突然中断,或者是任务已执行完且队列已清空
        processWorkerExit(w, completedAbruptly);
    }
}

processWorkerExit(Worker w, boolean completedAbruptly)

private void processWorkerExit(Worker w, boolean completedAbruptly) {
    // 如果工作线程是突然中断的,那么需要减少一个工作线程数量
    if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
        decrementWorkerCount();
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        // 将工作线程的完成任务数加到completeTaskCount,该变量的作用是记录当前线程池完成的任务总数
        completedTaskCount += w.completedTasks;
        // 从工作线程集合中移除任务
        workers.remove(w);
    } finally {
        mainLock.unlock();
    }
    // 尝试终止线程池,如果是工作线程的正常关闭,那么该方法会因为线程池状态的不符合直接返回
    tryTerminate();
    // 判断线程池状态是否在STOP之前,即RUNNING或SHUTDOWN
    int c = ctl.get();
    if (runStateLessThan(c, STOP)) {
        // 如果工作线程是正常结束的话
        if (!completedAbruptly) {
            // 判断最少工作线程数应该是多少
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            // 如果最少工作线程数为0,且任务队列不为空,说明最少需要一个线程来执行任务队列中的任务
            if (min == 0 && ! workQueue.isEmpty())
                min = 1;
            // 如果当前工作线程数大于等于最少线程数,那么说明工作线程数已经够了,直接返回即可
            if (workerCountOf(c) >= min)
                return; // replacement not needed
        }
        // 如果工作线程是非正常结束,或正常结束但是当前工作线程数小于最少工作线程数,那么就需要启动一个工作线程,来执行任务
        addWorker(null, false);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值