java 优雅关闭线程池的方案
作者:AnonyStar 发布时间:2022-03-20 23:05:44
我们经常在项目中使用的线程池,但是是否关心过线程池的关闭呢,可能很多时候直接再项目中直接创建线程池让它一直运行当任务执行结束不在需要了也不去关闭,这其实是存在非常大的风险的,大量的线程常驻在后台对系统资源的占用是巨大的 ,甚至引发异常。所以在我们平时使用线程池时需要注意优雅的关闭,这样可以保证资源的管控。
在 Java 中和关闭线程池相关的方法主要有如下:
void shutdown()
List<Runnable> shutDownNow
boolean awaitTermination
boolean isShutDown
boolean isTerminated
对于这些方法有着不同的使用和作用,下面我们真的会这些不同的方法做详细的介绍。
ShutDown
shutDown 方法从字面意思我们可以看到是停止关闭的意思,我们先来看下面的一段代码,首先我们通过 ThreadPoolExecutor 来创建一个容量是10的 * 线程池,与 FixedThreadPool 类似的,这里手动创建可以更好地理解线程池的创建。在后我们提交一千个任务执行,再执行 shutdown 方法进行暂停。
public static void main(String[] args) throws InterruptedException {
ExecutorService service = new ThreadPoolExecutor(
10,
10,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>());
for (int i = 0; i < 1000; i++) {
service.submit(() ->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("接受中断,不处理~~");
}
System.out.println("args = " + Arrays.deepToString(args)+ Thread.currentThread().getName());
});
}
service.shutdown();
}
我们可以看到结果所以线程会正常执行结束后再关闭线程池,对于 ShutDown 而言它可以安全的停止一个线程池,它有几个关键点
ShutDown 会首先将线程设置成 SHUTDOWN 状态,然后中断所有没有正在运行的线程
正在执行的线程和已经在队列中的线程并不会被中断,说白了就是使用shutDown 方法其实就是要等待所有任务正常全部结束以后才会关闭线程池
调用 shutdown() 方法后如果还有新的任务被提交,线程池则会根据拒绝策略直接拒绝后续新提交的任务。
ShutDownNow
这个方法与上面方法相比较,直观就是 now ,即立即停止任务,
同样是上述案列,略作修改如下,
public static void main(String[] args) throws InterruptedException {
ExecutorService service = new ThreadPoolExecutor(
10,
10,
0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(1000));
for (int i = 0; i < 1000; i++) {
service.submit(() ->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("接受中断,结束线程~~");
//这里响应中断
return;
}
System.out.println("args = " + Arrays.deepToString(args)+ Thread.currentThread().getName());
});
}
final List<Runnable> runnables = service.shutdownNow();
System.out.println(runnables);
}
执行上述代码我们发现,当执行shutDownNow 方法后,会像全部正在运行的队列通知中断,正在运行的线程接收到中断信号后选择处理,而在队列中的全部取消执行转移到一个list队列中返回,如上述 List<Runnable> runnables ,这里记录了所有终止的线程
awaitTermination
这个方法并不是用来关闭线程池的,首先我们看一下这个方法的定义:
boolean awaitTermination_(long timeout, TimeUnit unit)_
可以看到这个方法有两个参数,timeout 表示等待的时间,unit 时间单位
这个方法的作用是,调用后等待timeout时间后,反馈线程池的状态,
等待期间(包括进入等待状态之前)线程池已关闭并且所有已提交的任务(包括正在执行的和队列中等待的)都执行完毕,相当于线程池已经“终结”了,方法便会返回 true;
等待超时时间到后,第一种线程池“终结”的情况始终未发生,方法返回 false;
等待期间线程被中断,方法会抛出 InterruptedException 异常。
上面代码可以修改来测试,这里不再粘贴代码
isShutDown
isShutDown 方法正如名字,判断线程池是否停止,返回的是 Boolean 类型,如果已经开始停止线程池则返回 true 否则放回false
当调用了shutDown 或shutDownNow 时之后,会返回 true 不过需要注意,这时候只是代表线程池关闭流程的开始,并不是说线程池已经停止了
isTerminated
这个方法与上面的方法的区别就是这是正真检测线程池是否真的终结了
这不仅代表线程池已关闭,同时代表线程池中的所有任务都已经都执行完毕了,因为在调用 shutdown方法之后,线程池会继续执行里面未完成的任务,包括正在执行的任务和在任务队列中等待的任务。
如果调用了 shutdown 方法,但是有一个线程依然在执行任务,那么此时调用 isShutdown方法返回的是 true,而调用 isTerminated方法返回的便是 false,因为线程池中还有任务正在在被执行,线程池并没有真正“终结”。
直到所有任务都执行完毕了,调用 isTerminated()方法才会返回 true,这表示线程池已关闭并且线程池内部是空的,所有剩余的任务都执行完毕了。
作者:AnonyStar
原文链接:https://www.cnblogs.com/i-code/p/14024845.html
来源:https://www.cnblogs.com/i-code/p/14024845.html


猜你喜欢
- 前言emmm… 有个需求,需要根据信息生成svg,因为考虑到样式一致性的问题最终决定有服务端来生成svg。Java提供
- 1、需求说明,实现细节要求:解析二进制文件 files\case10\binary,其中包含一个字符串和一张图片,数据文件格式为字符串数据长
- 短网址(Short URL) ,顾名思义就是看起来很短的网址。自从twitter推出短网址服务以后,各大互联网公司都推出了自己的短网址服务。
- C# SynchronizationContext及Send和Post使用1、(SynchronizationContext)同步上下文的作
- 在实际项目开发过程中,我们经常需要对某个对象或者某个集合中的元素进行排序,常用的两种方式是实现某个接口。常见的可以实现比较功能的接口有Com
- SpringBoot版本:2.3.2.RELEASESpringBoot Data JPA版本:2.3.2.RELEASEJpaReposi
- 一、前言在SpringBoot工程(注意不是SpringCloud)下使OpenFeign的大坑。为什么不用SpringCloud中的Fei
- 本文实例展示了WinForm实现为ComboBox绑定数据源并提供下拉提示功能,这是一个非常有实用价值的功能,具体实现方法如下:主要功能代码
- Unity中的RegisterPlugins实用案例在Unity游戏开发中,我们经常需要使用第三方插件来实现一些特定的功能。为了让这些插件能
- Java集合的主要分为三种类型:• Set(集)• List(列表)• Map(映射)要深入理解集合首先要了解
- 一、Lambda表达式 1.1 函数式编程思想概述在数学中,函数就是有输入量、输出量的一套计算方案,也就是“拿
- where 子句用于指定类型约束,这些约束可以作为泛型声明中定义的类型参数的变量。1.接口约束。例如,可以声明一个泛型类 MyGeneric
- 数据库结构如下strategy中有外键member_id(关联member表)外键strategy_category(关联category表
- 创建SpringBoot项目,启动后,默认的访问路径即主机IP+默认端口号8080:http://localhost:8080/此时,我们就
- 最近在进行android开发过程中,在将 Intent传递给调用的组件并完成组件的调用时遇到点困难,并且之前对Intent的学习也是一知半解
- Mybatis使用@Select注解sql中使用inmapper@Select("SELECT u.* , ur.ro
- 序列帧动画经常用到,最直接的方式就是用Animation录制。但某些情况下这种方式并不是太友好,需要靠代码的方式进行序列帧动画的实现。代码实
- 关联篇:深入Android的消息机制源码详解-Handler,MessageQueue与Looper关系关联篇:Handler内存泄漏及其
- 这篇文章主要介绍了Java等待唤醒机制线程通信原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋
- 这篇文章主要介绍了如何基于java语言实现八皇后问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友