面试题:Java 线程池中 shutdown 与 shutdownNow 的区别是什么?

在 Java 的 ExecutorService 接口中,shutdown()shutdownNow() 都是用来关闭线程池的方法,但它们的行为和效果有所不同。理解两者之间的差异对于正确管理线程池的生命周期至关重要。

shutdown()

  • 行为:调用 shutdown() 方法后,线程池将不再接受新的任务提交,但是会继续执行已经提交的任务(包括那些已经在队列中等待执行的任务)。换句话说,它会平滑地关闭线程池。
  • 效果
    • 线程池的状态变为 SHUTDOWN
    • 已经提交的任务将继续执行直至完成。
    • 新的任务提交将会被拒绝,并抛出 RejectedExecutionException 异常。
  • 适用场景:当你希望确保所有已提交的任务都能够完成执行时使用此方法。
ExecutorService executorService = Executors.newFixedThreadPool(4);
executorService.submit(new MyTask());
// 提交其他任务...
executorService.shutdown(); // 不再接受新任务,但会完成已提交的任务

shutdownNow()

  • 行为:与 shutdown() 不同,shutdownNow() 尝试立即停止所有正在执行的任务,并暂停处理等待中的任务。该方法试图终止未开始的任务并返回一个等待执行的任务列表。
  • 效果
    • 线程池的状态变为 STOP
    • 尝试中断当前正在执行的所有任务。
    • 返回一个包含所有尚未开始执行的任务列表。
    • 正在运行的任务可能不会立即停止,取决于它们如何响应中断。
  • 适用场景:当你需要立即停止所有任务并且不关心未完成的任务时使用此方法。
ExecutorService executorService = Executors.newFixedThreadPool(4);
executorService.submit(new MyTask());
// 提交其他任务...
List<Runnable> notExecutedTasks = executorService.shutdownNow(); // 立即尝试停止所有任务
System.out.println("未执行的任务数量:" + notExecutedTasks.size());

主要区别

特性shutdown()shutdownNow()
是否接受新任务
对已提交任务的影响继续执行已提交任务尝试停止所有正在执行的任务,返回未开始的任务列表
线程池状态SHUTDOWNSTOP
阻塞调用线程直到所有任务完成可以通过 awaitTermination(...) 实现不会等待任务完成

注意事项

  • 使用 shutdownNow() 并不能保证所有的任务都会被立即中断或停止,因为并不是所有的任务都能响应中断请求。如果任务忽略了中断信号或者没有适当的中断处理逻辑,那么这些任务可能会继续执行。
  • 在调用了 shutdown() 或者 shutdownNow() 之后,可以使用 awaitTermination(long timeout, TimeUnit unit) 方法来等待线程池完成其任务,或者超时退出。这允许程序等待一段时间让线程池优雅地关闭。

了解这两者的区别有助于根据具体的应用需求选择合适的方式来关闭线程池,从而避免资源泄露或其他潜在问题。

THE END
喜欢就支持一下吧
点赞15 分享