ExecutorService 中 shutdown()、shutdownNow()、awaitTermination() 的区别及使用

引子

当没有任务需要执行时,ExecutorService 不会自动被系统销毁,而是会继续存活并等待新的任务到来。如果你的 app 需要随时响应处理新提交的任务,那 ExecutorService 的这种生命周期的设计就很合适。但是一个 app 总有结束的时刻,当 app 结束时,ExecutorService 却并不会终止,它将导致 JVM 继续存活并运行。shutdown 和 shutdownNow 就是为关闭 ExecutorService 而设计的 API。

一、方法说明

1、shutdown():停止接收新任务,原来的任务继续执行

英文原意:关闭,倒闭;停工。 这里的意思是  关闭线程池与使用数据库连接池一样,每次使用完毕后,都要关闭线程池。

1. 停止接收新的submit的任务;
2. 已经提交的任务(包括正在跑的和队列中等待的),会继续执行完成;
3. 等到第2步完成后,才真正停止;

2、shutdownNow():停止接收新任务,原来的任务停止执行

  1. 跟 shutdown() 一样,先停止接收新submit的任务;
  2. 忽略队列里等待的任务;
  3. 尝试将正在执行的任务interrupt中断;
  4. 返回未执行的任务列表;

说明:它试图终止线程的方法是通过调用 Thread.interrupt() 方法来实现的,这种方法的作用有限,如果线程中没有sleep 、wait、Condition、定时锁等应用, interrupt() 方法是无法中断当前的线程的。所以,shutdownNow() 并不代表线程池就一定立即就能退出,它也可能必须要等待所有正在执行的任务都执行完成了才能退出。但是大多数时候是能立即退出的。

3、awaitTermination(long timeOut, TimeUnit unit):当前线程阻塞

timeout 和 TimeUnit 两个参数,用于设定超时的时间及单位

当前线程阻塞,直到:

  • 等所有已提交的任务(包括正在跑的和队列中等待的)执行完;
  • 或者 等超时时间到了(timeout 和 TimeUnit设定的时间);
  • 或者 线程被中断,抛出InterruptedException

然后会监测 ExecutorService 是否已经关闭,返回true(shutdown请求后所有任务执行完毕)或 false(已超时)

二、区别

1、shutdown() 和 shutdownNow() 的区别

shutdown() 只是关闭了提交通道,用submit()是无效的;而内部该怎么跑还是怎么跑,跑完再停。
shutdownNow() 能立即停止线程池,正在跑的和正在等待的任务都停下了。

2、shutdown() 和 awaitTermination() 的区别

shutdown() 后,不能再提交新的任务进去;但是 awaitTermination() 后,可以继续提交。awaitTermination()是阻塞的,返回结果是线程池是否已停止(true/false);shutdown() 不阻塞。

三、最佳实践

终止 ExecutorService 的一个最佳实践就是,shutdown 和 shutdownNow 两个方法一起,并结合 awaitTermination 来实现超时等待。

executorService.shutdown();
try {
    if (!executorService.awaitTermination(800, TimeUnit.MILLISECONDS)) {
        executorService.shutdownNow();
    } 
} catch (InterruptedException e) {
    executorService.shutdownNow();
}
  1. 调用 shutdown,阻止新提交任务,并让等待队列中的任务执行完成
  2. 调用 awaitTermination(),保证等待队列中的任务最多执行 800 ms,以防止执行任务时间太长或被阻 塞,而导致 ExecutorService 不能被销毁。
  3. 在 awaitTermination 等待 800 ms 后,ExecutorService 中还有任务没执行完,则调用 shutdownNow 强行终止,以释放 ExecutorService 资源。
  4. 上面代码执行 awaitTermination 时所在的线程也有可能被 interrupt,因此需要 catch InterruptedException

原文:ExecutorService 中 shutdown()、shutdownNow()、awaitTermination() 的区别及使用 - 知乎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
`java.util.concurrent.ThreadPoolExecutor`是Java用于管理线程池的类。`shutdown()`和`shutdownNow()`都是用于关闭线程池的方法,但它们之间有一些区别。 - `shutdown()`方法:该方法将线程池状态设置为SHUTDOWN,不再接受新任务,但会等待所有已经提交的任务执行完成后再关闭线程池。如果在调用`shutdown()`方法后又提交了新任务,这些新任务将会被拒绝执行并抛出`RejectedExecutionException`异常。 - `shutdownNow()`方法:该方法将线程池状态设置为STOP,不再接受新任务,并尝试停止所有正在执行的任务,包括等待执行的任务。该方法会尝试断正在执行的任务,如果任务无法被断,则会保持运行状态。该方法返回一个`List<Runnable>`,其包含所有等待执行的任务。 以下是一个示例代码,演示了如何使用`ThreadPoolExecutor`类以及如何使用`shutdown()`和`shutdownNow()`方法: ```java import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class ThreadPoolExample { public static void main(String[] args) throws InterruptedException { // 创建一个线程池,最多同时执行2个任务 ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2); // 提交5个任务 for (int i = 0; i < 5; i++) { executor.submit(new Task(i)); } // 关闭线程池 executor.shutdown(); // 等待所有任务执行完成 executor.awaitTermination(1, TimeUnit.MINUTES); // 输出线程池状态 System.out.println("线程池状态:" + (executor.isTerminated() ? "已关闭" : "未关闭")); // 再次提交任务,会抛出RejectedExecutionException异常 executor.submit(new Task(5)); // 关闭线程池 executor.shutdownNow(); // 输出线程池状态 System.out.println("线程池状态:" + (executor.isTerminated() ? "已关闭" : "未关闭")); } static class Task implements Runnable { private int taskId; public Task(int taskId) { this.taskId = taskId; } @Override public void run() { System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName()); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Task " + taskId + " is interrupted"); } System.out.println("Task " + taskId + " is completed"); } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值