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

在 Java 线程池中,shutdown() 和 shutdownNow() 是用于关闭线程池的两个方法,但它们的行为和效果有显著区别。以下是它们的详细对比:


1. shutdown()

  • 行为
    • 平缓地关闭线程池。
    • 停止接受新任务,但会继续执行已提交的任务(包括正在执行的任务和队列中等待的任务)。
    • 调用后,线程池会进入 SHUTDOWN 状态。
  • 适用场景
    • 当你希望线程池完成所有已提交的任务后再关闭时使用。
  • 示例
    ExecutorService executor = Executors.newFixedThreadPool(2);
    executor.execute(() -> System.out.println("任务1"));
    executor.execute(() -> System.out.println("任务2"));
    executor.shutdown(); // 停止接受新任务,等待已提交任务完成

2. shutdownNow()

  • 行为
    • 立即尝试停止所有正在执行的任务,并停止处理队列中等待的任务。
    • 返回一个包含未执行任务的列表(List<Runnable>)。
    • 调用后,线程池会进入 STOP 状态。
    • 通过调用线程的 interrupt() 方法来尝试中断正在执行的任务(如果任务没有响应中断,则无法停止)。
  • 适用场景
    • 当你希望立即停止所有任务时使用。
  • 示例
    ExecutorService executor = Executors.newFixedThreadPool(2);
    executor.execute(() -> {
        try {
            Thread.sleep(1000);
            System.out.println("任务1");
        } catch (InterruptedException e) {
            System.out.println("任务1被中断");
        }
    });
    executor.execute(() -> System.out.println("任务2"));
    List<Runnable> notExecutedTasks = executor.shutdownNow(); // 立即停止所有任务
    System.out.println("未执行的任务数量: " + notExecutedTasks.size());

主要区别

特性shutdown()shutdownNow()
是否接受新任务停止接受新任务停止接受新任务
已提交任务的处理继续执行已提交的任务尝试停止所有任务(包括正在执行的任务)
队列中的任务继续执行队列中的任务清空队列并返回未执行的任务列表
线程池状态进入 SHUTDOWN 状态进入 STOP 状态
中断线程不会中断线程尝试中断所有线程
返回值无返回值返回未执行的任务列表

注意事项

  1. 任务的中断
    • shutdownNow() 会尝试中断正在执行的任务,但如果任务没有响应中断(例如没有检查 Thread.interrupted()),任务可能不会停止。
  2. 线程池的最终状态
    • 调用 shutdown() 或 shutdownNow() 后,线程池会进入终止状态(TERMINATED),但需要调用 awaitTermination() 来等待线程池完全关闭。
  3. 任务的中断处理
    • 如果任务需要支持中断,应该在任务中定期检查 Thread.interrupted() 或捕获 InterruptedException

总结

  • 使用 shutdown() 时,线程池会优雅地关闭,确保所有已提交的任务完成。
  • 使用 shutdownNow() 时,线程池会立即尝试停止所有任务,适合需要快速关闭的场景。
THE END
点赞11 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容