线程池的状态转换:

关闭线程池的方法
- shutdown():把线程池状态修改为SHUTDOWN,并通过interruptIdleWorkers()中断所有空闲工作者线程。
- shutdownNow():把线程池状态修改为STOP,移除队列中的任务并通过interruptWorkers()中断所有工作者线程。
shutdownNow()会中断正在工作的工作者线程,也仅仅是中断目标线程,但目标线程不一定响应中断或者已处理中断异常,它并不是停止目标线程。
线程池是如何判断工作者线程是空闲还是忙碌呢?
工作者线程Worker是继承AbstractQueuedSynchronizerd的,锁被占用时线程就是忙碌状态,锁空闲时线程就是空闲状态。
为什么要中断工作者线程?
中断空闲的工作者线程:因为线程可能在getTask()中的take()或者poll()方法处阻塞,通过中断就能够唤醒这些被阻塞的线程,然后这些被唤醒线程如果获取不到任务的话,就会被回收。
中断忙碌的工作者线程:主要是为了取消任务的执行,但不一定成功,因为任务不一定响应中断或则处理了中断异常。
线程池关闭的流程
在执行任何可能终止线程池的操作都会调用tryTerminate()去尝试关闭线程池,比如:
- processWorkerExit():工作者线程退出
- remove():移除队列中的某个任务
- purge():移除队列中已取消的任务
- shutdown():拒绝提交任务
- shutdownNow():拒绝提交任务并移除队列中的任务
tryTerminate()源码解析:
final void tryTerminate() {
for (;;) {
//线程池状态
int c = ctl.get();
// 线程池是运行状态
if (isRunning(c) ||
// 线程池是TIDYING或者TERMINATED状态
runStateAtLeast(c, TIDYING) ||
// 线程池是SHUTDOWN但是队列中还有任务
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
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 {
//默认的实现为一个空方法,用户可以重写它!
terminated();
} finally {
// 设置线程池的状态为TERMINATED
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
总结:
- 当线程池的状态为SHUTDOWN或STOP且任务队列为空且工作者线程数为0时,线程池就会进入TIDYING状态,当执行完terminated()方法后,就会进入最终的TERMINATED状态。
- 如果任务是一个死循环且不响应中断的话,那么这个线程池永远也不会被关闭。
2万+





