年底了,柴宝准备出去看看机会,看看最近的后端开发市场环境,收到了大厂面试邀请…
几天后,柴宝碰见了大柴......
提到线程池的关闭得先了解下线程池的状态:
- RUNNING:正常工作状态,在这个状态下,线程池接受新的任务并且处理已经提交的任务
- SHUTDOWN:关闭状态,不能接受新的任务。此时,线程池会等待已提交的任务执行完毕(队列中),不会再接受新的任务。
- STOP:停止状态,线程池中的所有任务都会被中断,线程池也不能接受新的任务。
- TIDYING:清理中状态,其实是个过渡态,当线程池的所有任务都已经完成,线程池进入此状态。在这个状态下,线程池会执行清理工作,比如释放资源等
- TERMINATED:结束状态,表示线程池已经完全终止,所有任务已经完成并且所有线程都已经退出,线程池不能再恢复
每个状态之间的转换:
总结:
- RUNNING → SHUTDOWN:调用 shutdown()
- RUNNING → STOP:调用 shutdownNow()
- SHUTDOWN → TIDYING:所有任务完成,工作线程退出
- TIDYING → TERMINATED:清理完成,线程池完全终止
线程池的关闭方法主要有三种:
(1)shutdown()
该方法用于优雅地关闭线程池。它会执行以下操作:
- 不再接受新任务。
- 等待所有已提交的任务执行完毕。
- 线程池中的线程将继续执行队列中的任务,直到任务队列为空或所有任务执行完毕。
该方法不会立即停止正在执行的任务,也不会中断那些正在运行的线程。
(2)shutdownNow()
shutdownNow() 方法尝试立即停止线程池。它会执行以下操作:
- 不再接受新任务。
- 尝试停止正在执行的任务。
- 返回一个列表,包含所有尚未开始执行的任务(这些任务将不会被执行)。
该方法试图通过中断正在执行的线程来停止任务,但不能保证任务立即终止,取决于任务本身是否响应中断。
(3)awaitTermination()
awaitTermination() 是用来配合 shutdown() 或 shutdownNow() 使用的,它会让当前线程(通常是主线程)等待直到线程池完全关闭或超时。该方法常用于确保线程池中的任务完成后再退出应用程序。
用法示例:
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> {
try {
Thread.sleep(2000);
System.out.println("Task completed");
} catch (InterruptedException e){
Thread.currentThread().interrupt();
}});
executor.shutdown(); // 不再接受新任务
// 等待线程池中的任务完成或超时
if (!executor.awaitTermination(5, TimeUnit.SECONDS))
{
System.out.println("Timeout: Forcefully shutting down the executor");
executor.shutdownNow(); // 如果超时,强制关闭线程池
}
- awaitTermination()会让主线程等待,直到线程池中的所有任务完成,或者超时。
- 通常配合 shutdown() 使用,确保线程池完全关闭后再继续程序执行。
(4)isShutdown() 和 isTerminated()
- isShutdown() 方法返回一个布尔值,指示线程池是否已经关闭(即已调用 shutdown() 或 shutdownNow())
- isTerminated() 方法返回一个布尔值,指示线程池是否已经完全终止(即所有任务都已完成或已被中断)
总结
-
优雅关闭:使用 shutdown(),会等待已提交任务执行完成,不再接受新任务。
-
强制关闭:使用 shutdownNow(),会尝试立即停止线程池,并返回未开始执行的任务。
-
等待线程池完全关闭:使用 awaitTermination(),配合shutdown() 或 shutdownNow() 使用,可以等待线程池完全关闭或直到超时。
-
检查线程池状态:使用 isShutdown() 和 isTerminated() 检查线程池的状态。
在关闭线程池时,通常建议使用 shutdown() 方法,并配合 awaitTermination() 来确保线程池的优雅关闭。如果需要立即停止线程池中的任务,可以使用 shutdownNow()。