ThreadPoolExecutor 的关闭流程很简单
void shutdown()
1. 获取 mainLock 锁
2. 当前的状态如果是 SHUTDOWN ,STOP ,TIDYING ,TERMINATED 则退出
3. 如果不是则 CAS 设置状态为 SHUTDOWN
4. CAS 失败则回到 step 2 继续
5. 对所有 Worker
线程调用 interrupt() 中断阻塞
6. 释放 mainLock ,调用 tryTerminate() 关闭线程池 ( tryTerminate()的流程请看 http://vampiredx.iteye.com/blog/2211153 )
step 5 中断所有线程后,新的任务不能再提交进来,但是 worker 线程并不会立即退出,会继续从 workQueue 取出并执行任务,直到没有任务后再退出。所以调用 shutdown() 的线程在这里不会被阻塞,线程池会等待 workQueue 里面所有任务执行完毕以后才会变成 TERMINATED。
void tryTerminate()
1. 获取当前的线程数量,线程池状态
2. 如果线程池状态是 RUNNING、 TIDYING、 TERMINATED 直接返回
3. 如果线程池是 SHUTDOWN,但是 workQueue 还有 task,直接返回
4. 到这步,线程池状态应该是 SHUTDOWN 并且 workQueue 已经没有 task,或者是 STOP。如果线程池里面还有线程存活,call interruptIdleWorkers(true) 从 workers 里面去关闭一个闲置线程 (为什么只关闭一个?),return
5. 到这步,线程池状态应该是 SHUTDOWN 或者 STOP,workQueue 已经没有 task,线程池里面没有线程存活。获取 mainLock, CAS 操作设置状态为 TIDYING 。如果 CAS 成功,则再次设置状态为 TERMINATED, call termination.signalAll()唤醒等待线程池关闭的线程(外部线程可能 call awaitTermination(long timeout, TimeUnit unit)等待线程池彻底关闭)
6. 释放mainLock
这里的疑惑为 step 4,当线程池里面还有线程存活的时候,尝试去关闭最多一个线程。为什么是只关闭最多一个?而不是全部?注意 step 5,CAS操作设置状态为 TIDYING 。这是因为前面检查状态都是在没获取 mainLock 情况下完成的,在获取 mainlock 后重复检查成功,之后才设置 TERMINATED 状态并唤醒等待线程池关闭的线程
List<Runnable> shutdownNow()
1. 获取 mainLock 锁
2. 当前的状态如果是 STOP ,TIDYING ,TERMINATED 则退出
3. 如果不是则 CAS 设置状态为 STOP
4. CAS 失败则回到 step 2 继续
5. 对所有 Worker 线程调用 interrupt() 中断阻塞
6. 从 workQueue 里面取出所有任务,
7. 释放 mainLock ,调用 tryTerminate() 关闭线程池。返回 workQueue 里没有被执行的任务。
shutdownNow() 和 shutdown() 流程很类似,但是调用后不会等待 Worker 线程继续执行已经提交任务。相反,当前调用线程会取出任务返回。
boolean awaitTermination(long timeout, TimeUnit unit)
1. 获取 mainLock 锁
2. 当前的状态如果是 TERMINATED 则返回 true
3. 如果不是,使用和 mainLock 关联的条件 termination.awaitNanos(nanos) 等待 指定时间,
超时后状态还不是 TERMINATED。 返回false。
4. 释放 mainLock 锁
调用 awaitTermination 的线程会被阻塞最多指定时间,最后是否关闭线程池成功需要判断返回值。
Java ThreadPoolExecutor 学习笔记(一)
Java ThreadPoolExecutor 学习笔记(二)