Java 线程池中 shutdown 与 shutdownNow 的区别是什么?
Java 线程池中 shutdown 与 shutdownNow 的区别是什么?
重点回答
shutdown() 和 shutdownNow() 都用于关闭线程池,但工作方式有所不同:
1)**shutdown()**:
启动线程池的平滑关闭。它不再接受新的任务,但会继续执行已经提交的任务(包括在队列中的任务)。
线程池会进入 SHUTDOWN 状态,所有已执行和正在执行的任务都会继续完成,只有所有任务完成后,线程池才会完全终止。
2)**shutdownNow()**:
启动线程池的强制关闭。它会尝试停止所有正在执行的任务,并返回等待执行的任务列表。它会尽力中断正在执行的任务,但不能保证所有任务都能被立即停止。
线程池进入 STOP 状态,除了尝试中断正在执行的任务外,还会清空任务队列,返回未执行的任务列表。
使用场景:
- **
shutdown()**:适用于程序需要平滑停止线程池的场景,如应用程序正常退出时。保证所有已提交的任务都能执行完毕,避免任务丢失。 - **
shutdownNow()**:适用于紧急情况或需要立即停止线程池的场景,如应用程序异常退出时。快速清理资源,但可能导致部分任务未完成。
扩展知识
shutdownNow 的尝试中断
shutdownNow() 会通过调用 Thread.interrupt() 来中断线程,但这取决于任务实现的具体中断响应方式。如果任务在执行过程中没有正确处理中断(如未检查 Thread.interrupted() 状态),则无法强制中断。

还有,使用 shutdownNow() 时,返回的任务列表包含所有未执行的任务。我们可以选择将这些任务重新提交到另一个线程池或进行其他处理(日志记录、落库等等)。
线程池生命周期:
- 运行状态(RUNNING):线程池可以接受新任务并处理已提交的任务。
- 关闭状态(SHUTDOWN):通过调用
shutdown()进入,该状态下线程池不再接受新任务,但会继续执行已有的任务。 - 停止状态(STOP):通过调用
shutdownNow()进入,该状态下线程池会试图中断所有正在执行的任务并清空任务队列。 - 终止状态(TERMINATED):所有任务执行完毕且线程池完全关闭后,线程池进入
TERMINATED状态。
结合 awaitTermination:
无论是 shutdown() 还是 shutdownNow(),可以配合 awaitTermination() 方法等待线程池完全终止。awaitTermination() 会阻塞调用线程,直到线程池终止或超时。
比如以下的使用方式:
1 | threadPool.shutdown(); |
这种组合方式常用于确保线程池能够在合理时间内关闭,避免无限等待或资源泄漏。
多次调用 shutdown()或shutdownNow() 会怎样?
调用 shutdown() 或 shutdownNow() 后,再次调用它们不会有额外效果。shutdownNow() 只会在第一次调用时有效果。
并且,即使线程池进入 SHUTDOWN 状态,相关资源不会立即释放。必须等待所有线程完成任务,线程池进入 TERMINATED 状态后,资源才会释放。