网站一级域名aspcms网站源码
Java 线程池中 shutdown 与 shutdownNow 的区别
- 核心行为差异
| 方法 | 行为描述 |
|----------------|----------------------------------------------------------------------------|
|shutdown| 平缓关闭线程池:
1. 停止接受新任务。
2. 已提交的任务(包括队列中的任务)会继续执行完成。 |
|shutdownNow| 强制关闭线程池:
1. 停止接受新任务。
2. 尝试中断正在执行的任务。
3. 清空任务队列,并返回未执行的任务列表。 |
- 线程中断机制
-
shutdown:- 不中断任何线程,正在执行的任务会继续运行直到完成。
- 适用于需要确保所有已提交任务完整执行的场景(如数据持久化)。
-
shutdownNow:- 向所有工作线程发送中断信号(调用
Thread.interrupt())。 - 任务是否终止取决于代码逻辑:
- 若任务未检查中断状态(如未捕获
InterruptedException),可能无法终止。 - 示例:一个循环任务中未调用
Thread.currentThread().isInterrupted(),即使调用shutdownNow,任务仍会继续运行。
- 若任务未检查中断状态(如未捕获
- 向所有工作线程发送中断信号(调用
- 任务队列处理
| 方法 | 队列处理 | 返回值 |
|----------------|----------------------------------------------------------------------------|------------------------------|
|shutdown| 继续执行队列中所有任务。 | 无返回值。 |
|shutdownNow| 移除并丢弃队列中所有未执行的任务,返回这些任务的列表(List<Runnable>)。 | 返回未执行任务的列表。 |
- 线程池状态变化
-
shutdown:- 将线程池状态从
RUNNING改为SHUTDOWN。 - 最终状态会过渡到
TERMINATED(需所有任务执行完毕)。
- 将线程池状态从
-
shutdownNow:- 将线程池状态从
RUNNING改为STOP。 - 最终状态过渡到
TERMINATED(无论任务是否全部完成)。
- 将线程池状态从
- 适用场景
| 方法 | 典型场景 |
|----------------|----------------------------------------------------------------------------|
|shutdown| 需要确保所有任务完整执行(如数据库批量写入、日志归档)。 |
|shutdownNow| 紧急终止线程池(如服务宕机前快速释放资源,或处理死锁任务)。 |
实战建议
-
优雅关闭的最佳实践:
- 先调用
shutdown,再通过awaitTermination等待任务完成。 - 若超时未完成,再调用
shutdownNow强制终止。
executor.shutdown(); try {if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {executor.shutdownNow(); // 超时后强制终止 } } catch (InterruptedException e) {executor.shutdownNow(); } - 先调用
-
任务代码的容错设计:
- 在任务中定期检查中断状态,确保能响应
shutdownNow。
public void run() {while (!Thread.currentThread().isInterrupted()) {// 执行任务逻辑 } } - 在任务中定期检查中断状态,确保能响应
-
监控与日志:
- 记录
shutdownNow返回的未执行任务列表,用于故障恢复或重试。
- 记录
扩展:源码级逻辑
shutdown:- 仅修改线程池状态为
SHUTDOWN,后续执行完队列任务后触发terminate()。
- 仅修改线程池状态为
shutdownNow:- 修改状态为
STOP,中断所有工作线程,并清空队列。 - 源码片段:
public List<Runnable> shutdownNow() {List<Runnable> tasks;final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {checkShutdownAccess();advanceRunState(STOP); // 状态改为STOP interruptWorkers(); // 中断所有线程 tasks = drainQueue(); // 清空队列并返回未执行任务 } finally {mainLock.unlock();}tryTerminate();return tasks; }
- 修改状态为
总结
shutdown是“礼貌告别”,确保任务善后。shutdownNow是“强制清场”,适合紧急场景,但依赖任务代码的健壮性。- 关键选择点:是否需要保留未执行任务?能否容忍任务中途终止?
