背景

在Java开发中,如果涉及多线程,会经常使用到线程池,本期不额外讲述线程池本身相关的东西。考虑一种场景,如果我们提交给线程池的任务都相对比较耗时,而在任务启动运行后,如果后续有需求的变更,要重新部署业务。

这时,需要关闭当前的执行实例或者重启,如果直接kill实例而任务又包含多个复杂的逻辑,可能导致一些非预期的后果。因此,类似情况下,需要等线程池中已有任务尽量执行完毕,来避免带来意料以外的问题。当然本身的

threadPoolExecutor是带有相关处理机制的,下面就介绍对应方法以及使用。

线程池停止

threadPoolExecutor 提供了两个线程池停止方法shutdown(),shutdownNow()。首先shutdown()将状态转换为shutdown,方法不会阻塞,没有返回值;shutdownNow()将状态转换为stop,方法不会阻塞,返回线程池队列中等待执行的任务列表。如果要等待任务执行完毕,就要和另一个方法配合实现,即awaitTermination()。如下代码,后面做解释说明。

代码

static ThreadPoolExecutor executorService = new ThreadPoolExecutor(5, 5, 1, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10));

@Test

public void executorTest() throws InterruptedException {

//用来监控线程池的执行状态,注意初始化用ThreadPoolExecutor,非executorService

Thread t = new Thread(() -> {

while (true) {

try {

System.out.println(executorService);

TimeUnit.SECONDS.sleep(3);

} catch (Exception e) {

e.printStackTrace();

}

}

});

t.start();

//记录执行时间

long start = System.currentTimeMillis();

for (int i = 0; i < 10; i++) {

int x = i;

CompletableFuture.runAsync(() -> {

try {

System.out.println("running..." + x);

if (x == 7) {

TimeUnit.SECONDS.sleep(20);

}else {

TimeUnit.SECONDS.sleep(5);

}

} catch (Exception e) {

e.printStackTrace();

}

}, executorService).toCompletableFuture().whenComplete((aVoid, throwable) -> {

//每个任务执行完成的需要的时间

System.out.println(System.currentTimeMillis() - start);

});

}

//执行shutdown

if (!executorService.isShutdown()) {

executorService.shutdown();

System.out.println("start shutdown ...");

//等待执行结束

executorService.awaitTermination(2, TimeUnit.MINUTES);

}

}

执行结果

java.util.concurrent.ThreadPoolExecutor@1866f339[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]

running...0

running...1

running...2

running...3

running...4

start shutdown ...

java.util.concurrent.ThreadPoolExecutor@1866f339[Shutting down, pool size = 5, active threads = 5, queued tasks = 5, completed tasks = 0]

5003

running...5

5004

5004

5004

running...7

running...6

5004

running...8

running...9

java.util.concurrent.ThreadPoolExecutor@1866f339[Shutting down, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 5]

java.util.concurrent.ThreadPoolExecutor@1866f339[Shutting down, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 5]

10003

10005

10005

10005

java.util.concurrent.ThreadPoolExecutor@1866f339[Shutting down, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 9]

java.util.concurrent.ThreadPoolExecutor@1866f339[Shutting down, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 9]

java.util.concurrent.ThreadPoolExecutor@1866f339[Shutting down, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 9]

java.util.concurrent.ThreadPoolExecutor@1866f339[Shutting down, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 9]

java.util.concurrent.ThreadPoolExecutor@1866f339[Shutting down, pool size = 1, active threads = 1, queued tasks = 0, completed tasks = 9]

25005

解析

这里使用了awaitTermination和shutdown来配合,可以看到最终的执行时间是25s,即一般线程5秒和最长线程20s的和,这里用id=7的为最长,可以实验下,如果改成id=4为最长执行时间,因为4<5,5是核心线程池

数,id=4就属于所有任务前半部分(先提交的部分),所有任务最长执行时间约20s。有人会问,为什么不用shutdownNow,因为shutdownNow会将所有的执行线程设置为interrupt,包括正在活跃的。而shutdown只将空闲等待状态的线程做状态变更,不会影响正在执行的。

可以试验下,如果改成shutdownNow,后续任务是没法执行成功的。 其中sleep会被interrupt打断。

总结

以上就是本期的内容,注意awaitTermination,有超时设置,可以避免一直阻塞,实现是用condition的waitNanos, 同时一定要配合shutdown使用,避免不必要的等待时间,意思就是先shutdown然后再awatiTermination。

java 等待线程池结束_等待线程池中任务执行完毕做优雅关闭相关推荐

  1. linux 查询线程是否结束_批量随机键值查询测试

    [摘要] 当数据量巨大时,使用大批量随机键值集获取对应记录集合,不仅仅考验数据库软件本身,更在于程序员对数据的理解!如何在硬件资源有限的情况下将性能发挥到极致?点击:批量随机键值查询测试,来乾学院一探 ...

  2. python两个线程交替打印_三线程按顺序交替打印ABC的四种方法

    建立三个线程A.B.C,A线程打印10次字母A,B线程打印10次字母B,C线程打印10次字母C,但是要求三个线程同时运行,并且实现交替打印,即按照ABCABCABC的顺序打印. 二.Synchroni ...

  3. python线程异常中断_中断线程

    如果线程需要执行一个长时间任务,就可能需要能中断线程.中断线程就是其他线程给该线程发一个信号,该线程收到信号后结束执行run()方法,使得自身线程能立刻结束运行. 我们举个栗子:假设从网络下载一个10 ...

  4. java scanner以回车结束_大佬看了直呼内行,你当初Java刚入门是否也是这样写代码?...

    1.集成开发环境 IDEA是一个专门针对Java的集成开发工具(IDE),由Java语言编写.所以,需要有JRE运行环境并配置好环境变量.它可以极大地提升我们的开发效率.可以自动编译,检查错误. 2. ...

  5. 平流式隔油池计算_广州隔油池清理公司讲述清理隔油池程序和标准_新闻中心...

    广州隔油池清理公司讲述清理隔油池程序和标准_隔油池清理,清理隔油池,隔油池清理方案,隔油池清理公司,隔油池清理价格 1.?隔油池/内污水油每月定期清理一次,若检查发现污水油超标以致可能影响隔油池有效性 ...

  6. java低层源码_如何查看javaJDK中底层源码

    展开全部 在初次使用java时,往往我32313133353236313431303231363533e4b893e5b19e31333363393735们对最基本的java类会忽略对其内部基本的实现 ...

  7. java 等待线程池结束_如何等待java线程池中所有任务完成

    一.等待线程池所有线程完成: 有时候我们需要等待java thread pool中所有任务完成后再做某些操作,如想要等待所有任务完成,仅需调用threadPool.awaitTermination() ...

  8. java修改线程池名称_自定义线程池的名称(ThreadPoolExecutor)

    目的:有时候为了快速定位出现错误的位置,在采用线程池时我们需要自定义线程池的名称. 1.创建ThreadFactory(ThreadPoolExecutor默认采用的是DefaultThreadFac ...

  9. java线程报时代码_什么?一个核同时执行两个线程?

    CPU里的时间 在我所在的CPU这座工厂里,时间的概念有些不太一样.工厂大门外的中央广场上挂着一个大大的钟表,整个计算机世界里的居民能够掐着时间过日子全都仰仗它,你们人类把它叫做晶振. 这个钟表每隔6 ...

最新文章

  1. Occupancy Networks:基于学习函数空间的三维重建表示方法
  2. charts混合使用 elementui和e_vue模块化(echart+element ui)
  3. 公式没有编号_知乎公式编辑器的一些小技巧 amp; 使用规范
  4. 从 25 倍稀释下的蘑菇街期权说起
  5. python中常用的序列化模块_Python中的序列化和反序列化
  6. php5中Xdebug配置安装步骤介绍
  7. 无法全新安装_好墙板更需好安装:护墙板安装新方法
  8. H264编码 封装成MP4格式 视频流 RTP封包
  9. oracle_Grid Infrastructure 启动的五大问题
  10. 绩效管理这样做,成本减半,员工叫好!
  11. 零基础学python大概要多久-怎么自学python,大概要多久?
  12. Power Query 系列 (04) - 从 Web 导入数据
  13. voip和rtc_VOIP的发展进化史
  14. 蓝牙BT射频测试(转发)
  15. 数据结构WSADATA
  16. DataSource
  17. csdn前200的大牛
  18. 微信电子健康卡开放平台接口对接
  19. 编程题——真题训练一(WYYX)
  20. 配置fly.js请求

热门文章

  1. Tag文件和Tag标记的用法详解
  2. 惠普测试c语言,HP的分院测试转自HP超话
  3. 玩游戏4g计算机的内存不足,别再说内存不足了!教你一招彻底解决,电脑运行加速3倍!...
  4. 【FatFs】手动移植FatFs,将SRAM虚拟U盘
  5. AS400 - DB2 for i的加密、解密
  6. ROS中一个关于时间的函数
  7. C语言 五子棋游戏(也可n子棋)
  8. Matlab在不同坐标系中绘图(对数、极坐标、双轴图)以及极坐标和直角坐标的相互转换
  9. 如何将pdf等非标准数据文件转换成可供EXCEL等软件分析的数据
  10. 英文影视网站视频资讯文章采集批量翻译发布