问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

ExecutorService线程池关闭方式详解

创作时间:
作者:
@小白创作中心

ExecutorService线程池关闭方式详解

引用
CSDN
1.
https://m.blog.csdn.net/weixin_45428910/article/details/145359103

ExecutorService提供了多种关闭线程池的方法,每种方式都有其适用场景和特点。本文将详细介绍这些关闭方式及其区别,并通过示例代码帮助读者更好地理解如何在实际开发中使用它们。

1. 关闭线程池的几种方式

1.1 shutdown()

作用:

  • 平缓关闭线程池。
  • 停止接受新任务,同时等待已提交的任务(包括正在执行的和队列中的任务)执行完成。

特点:

  • 不会强制中断正在运行的线程。
  • 可以配合 awaitTermination() 等待线程池完全关闭。

适用场景:

  • 程序需要保证已提交任务全部执行完毕。

示例:

ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> System.out.println("任务1执行"));
executor.submit(() -> System.out.println("任务2执行"));
executor.shutdown(); // 停止接受新任务
try {
    if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
        System.out.println("线程池未完全关闭");
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

1.2 shutdownNow()

作用:

  • 强制关闭线程池。
  • 尝试中断正在运行的线程,并清空任务队列中的所有待执行任务。

特点:

  • 返回未执行的任务列表。
  • 线程池中已运行的任务可能无法正常完成。
  • 强制中断的任务是否生效,取决于任务是否响应中断(例如,通过检查 Thread.interrupted())。

适用场景:

  • 需要尽快停止线程池,不关心未完成任务。

示例:

ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> {
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        System.out.println("任务被中断");
    }
});
List<Runnable> unexecutedTasks = executor.shutdownNow(); // 强制关闭
System.out.println("未执行的任务数量: " + unexecutedTasks.size());

1.3 awaitTermination()

作用:

  • 配合 shutdown() 使用,用于等待线程池中的任务在指定时间内完成。

特点:

  • 如果在指定时间内所有任务都完成,返回 true;否则返回 false
  • 必须在调用 shutdown()shutdownNow() 之后使用。

适用场景:

  • 需要阻塞主线程,等待线程池完成所有任务或超时退出。

示例:

executor.shutdown();
try {
    boolean terminated = executor.awaitTermination(5, TimeUnit.SECONDS);
    if (terminated) {
        System.out.println("所有任务完成");
    } else {
        System.out.println("等待超时,线程池未关闭");
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

1.4 isShutdown() 和 isTerminated()

作用:

  • isShutdown():判断线程池是否调用了 shutdown()shutdownNow()
  • isTerminated():判断线程池是否已完全终止(即所有任务都已完成)。

特点:

  • isShutdown() 只能判断是否关闭线程池,不判断任务是否执行完。
  • isTerminated() 确保所有任务执行完毕后返回 true

适用场景:
用于监控线程池状态。

示例:

executor.shutdown();
System.out.println("是否调用 shutdown(): " + executor.isShutdown());
System.out.println("是否完全终止: " + executor.isTerminated());

2. 关闭方式的区别

3. 使用建议

  • 推荐使用 shutdown()

  • 在大多数情况下,shutdown() 是首选,确保线程池内所有任务能够有序完成。

  • 避免滥用 shutdownNow()

  • 只有在必须强制停止任务的场景下使用,并确保任务能够正确处理中断。

  • 结合 awaitTermination() 使用:

  • 配合 shutdown(),为任务提供合理的完成时间,避免主线程提前退出。

  • 监控线程池状态:

  • 使用 isShutdown()isTerminated() 确保线程池的状态符合预期。

4. 示例:完整演示关闭线程池

import java.util.concurrent.*;

public class ThreadPoolShutdownExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        // 提交任务
        for (int i = 1; i <= 5; i++) {
            int taskNumber = i;
            executor.submit(() -> {
                System.out.println(Thread.currentThread().getName() + " 正在执行任务 " + taskNumber);
                try {
                    Thread.sleep(2000); // 模拟任务执行耗时
                } catch (InterruptedException e) {
                    System.out.println("任务 " + taskNumber + " 被中断");
                }
            });
        }
        // 关闭线程池
        executor.shutdown();
        try {
            if (!executor.awaitTermination(10, TimeUnit.SECONDS)) {
                System.out.println("任务未完成,强制关闭线程池...");
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
        System.out.println("线程池是否完全终止: " + executor.isTerminated());
    }
}

通过这些关闭方式的结合,可以根据具体需求选择适合的线程池关闭策略,保证程序的稳定性与效率。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号