线程池源码解析—shutdown/Now() & tryTerminate() 方法
shutdown()
- shutdown 就是将线程池状态设置为
SHUTDOWN
,然后中断所有空闲(空闲即阻塞在队列上)的线程,最终设置线程池状态为TERMINATED
。
/*
* 线程池状态变为 SHUTDOWN
* 不会接收新任务
* 但已提交任务会执行完
* 此方法不会阻塞调用线程的执行(不会等待线程池中所有的线程都执行完毕 才结束该方法)
*/
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
// 加锁(全局锁)
mainLock.lock();
try {
// 判断权限
checkShutdownAccess();
// 设置线程池状态为SHUTDOWN
advanceRunState(SHUTDOWN);
// 中断空闲线程
interruptIdleWorkers();
// 空方法,留给子类实现
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
// 解锁
mainLock.unlock();
}
// 下面有讲
tryTerminate();
}
advanceRunState()
// 自旋 + CAS 重新运算后为ctl赋值
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
/*
* 条件成立:假设传来的 targetState == SHUTDOWN,说当前线程池状态 >= SHUTDOWN
* 条件不成立:假设传来的 targetState == SHUTDOWN,说明当前线程池状态时RUNNING
* 强制更新一下当前线程池状态
*/
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
interruptIdleWorkers()
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
||
||
\/
/*
* @param onlyOne = true,说明只中断一个线程,false则中断所有线程
* 中断的前提是worker处于空闲状态
*/
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
// 持有全局锁 进行加锁
mainLock.lock();
try {
// 遍历所有的worker
for (Worker w : workers) {
// 拿到worker内部的线程
Thread t = w.thread;
/*
* 条件1成立:当前遍历的这个线程尚未中断
* 条件2成立:说明当前worker处于空闲状态,可以给它一个中断信号
* 目前worker内的线程在queue.take() | queue.poll()阻塞中
* 因为worker执行任务的时候是加锁的,能拿到锁说明当前没有在执行任务
*/
if (!t.isInterrupted() && w.tryLock()) {
try {
/*
* 给当前线程中断信号,处于queue阻塞的线程,会被唤醒,
* 唤醒后,进入下一次的自旋,可能会return null,执行退出相关的逻辑
*/
t.interrupt();
} catch (SecurityException ignore) {
} finally {
// 释放worker的独占锁
w.unlock();
}
}
// 判断是否只中断一个线程
if (onlyOne)
break;
}
} finally {
// 释放全局锁
mainLock.unlock();
}
}
shutdownNow()
- 设置线程池状态为
STOP
,将队列中的任务导出,最终中断所有空闲线程,然后调用 tryTerminate() 彻底关闭线程池
/*
* 线程池状态变为 STOP
* 不会接收新任务
* 会将队列中的任务返回
* 并用 interrupt 的方式中断正在执行的任务
*/
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
// 添加全局锁
mainLock.lock();
try {
checkShutdownAccess();
// 设置线程池状态为STOP
advanceRunState(STOP);
// 中断线程池中所有的线程
interruptWorkers();
// 将任务队列中的任务全部remove,然后导出到集合中
tasks = drainQueue();
} finally {
// 解锁
mainLock.unlock();
}
// 下面有讲
tryTerminate();
// 返回任务队列中未处理的任务
return tasks;
}
interruptWorkers()
- 中断所有空闲的线程
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
// 加锁
mainLock.lock();
try {
// 遍历所有worker
for (Worker w : workers)
// 如果worker内的thread是启动状态,则给它一个中断信号
w.interruptIfStarted();
} finally {
// 释放全局锁
mainLock.unlock();
}
}
tryTerminate()
- 判断当前线程池的状态,是否应该被设置为
TERMINATED
。
final void tryTerminate() {
// 自旋
for (;;) {
// 获取最新的ctl值
int c = ctl.get();
/*
* 条件1:当前线程池处于running状态,说明线程池很正常!直接返回。
* 条件2:当期线程池状态已经至少是TIDYING了,已经有其它线程在执行 TIDYING -> TERMINATED 状态了,当前线程直接返回。
* 条件3:SHUTDOWN的特殊情况(队列中还有任务),得等队列中的任务处理完毕后,再转换状态。
* 满足一个条件直接return,不允许转换状态。
*/
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
/*
* 什么时候会来到这里?
* 1.线程池状态 >= STOP
* 2.线程池状态为SHUTDOWN,并且队列已经空了
* 条件成立:当前线程池中的线程数量 > 0
*/
if (workerCountOf(c) != 0) {
/*
* 中断一个空闲线程(空闲就是处于获取任务的阻塞状态)
* 空闲线程,在哪空闲呢? queue.take() | queue.poll()
* 1.唤醒后的线程 会在getTask()方法返回null
* 2.执行退出逻辑的时候会再次调用tryTerminate() 唤醒下一个空闲线程
* 3.因为线程池状态是(线程池状态 >= STOP || 线程池状态为 SHUTDOWN 且 队列已经空了)最终调用addWorker时,会失败。
* 最终空闲线程都会在这里退出,非空闲线程 当执行完当前task时,也会调用tryTerminate方法,有可能会走到这里。
*/
interruptIdleWorkers(ONLY_ONE);
// 直接return
return;
}
/*
* 执行到这里的线程是哪个线程?最后一个退出的线程。workerCountOf(c) == 0 时会来到这里
* 在(线程池状态 >= STOP || 线程池状态为SHUTDOWN 且队列已经空了),
* 线程唤醒后,都会执行退出逻辑,退出过程中,会先将workerCount-1 => ctl — 1,
* 调用tryTerminate方法之前,已经减过了,所以0时,表示这是最后一个退出的线程
*/
final ReentrantLock mainLock = this.mainLock;
// 加锁
mainLock.lock();
try {
// 设置线程池状态为TIDING,线程数为0
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
// 钩子方法 留给子类实现的
terminated();
} finally {
// 最后设置线程池状态为最终的TERMINATED
ctl.set(ctlOf(TERMINATED, 0));
// termination(Condition),唤醒所有等待队列中的线程
termination.signalAll();
}
return;
}
} finally {
// 解锁
mainLock.unlock();
}
}
}
参考