线程池源码解析 shutdown/Now()方法
1.shutdown
shutdown就是将线程池状态设置为SHUTDOWN,然后中断所有空闲(空闲即阻塞在队列上)的线程,最终设置线程池状态为Terminated。
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
//加锁(全局锁)
mainLock.lock();
try {
checkShutdownAccess();
//设置线程池状态为SHUTDOWN。
advanceRunState(SHUTDOWN);
//中断空闲线程。
interruptIdleWorkers();
//空方法,留给子类实现
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
//解锁
mainLock.unlock();
}
tryTerminate();
}
2.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;
}
}
3.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;
/*
* 条件一成立: 当前遍历的这个线程尚未中断
* 条件二成立: 说明当前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();
}
}
4.shutdownNow()
// 将队列中的任务导出,最终中断所有空闲线程,然后调用tryTerminate()彻底关闭线程池
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;
}
5.interruptWorkers()
//中断所有空闲的线程
private void interruptWorkers()
{
final ReentrantLock mainLock = this.mainLock;
//加锁
mainLock.lock();
try {
//遍历所有worker
for (Worker w : workers)
//如果worker内的thread是启动状态,则给它一个中断信号。
w.interruptIfStarted();
} finally {
//释放全局锁
mainLock.unlock();
}
}
6.tryTerminate()
final void tryTerminate() {
//自旋
for (;;) {
//获取最新的ctl值
int c = ctl.get();
/*
* 条件一:当前线程池处于running状态,
* 条件二:当期线程池状态已经至少是TIDYING了
* 条件三: SHUTDOWN的特殊情况(队列中还有任务)
* 满足一个条件直接return,不允许装换状态。
*/
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
/*
* 什么时候会来到这里,
* 1.线程池状态 >= STOP
* 2.线程池状态为SHUTDOWN,并且队列已经空了。
*
* 条件成立:当前线程池中的线程数量 > 0
*/
if (workerCountOf(c) != 0) {
/*
* 中断一个空闲线程。(空闲就是处于获取任务的阻塞状态)唤醒后的线程会在getTask()中返回NULL
*/
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();
}
}
}