ExecutorService让我们可以优雅地在程序中使用线程池来创建和管理线程,而且性能佳、开销小,还可以有效地控制最大并发线程数,是我们在java并发编程中会经常使用到的。
每一个线程都会占用系统资源,因此线程池的关闭与清理同样重要,本文介绍我们如何优雅地关闭线程池。
停止接收新任务,原来的任务继续执行
停止接收新任务,原来的任务停止执行
说明:它试图终止线程的方法是通过调用 Thread.interrupt() 方法来实现的,这种方法的作用有限,如果线程中没有sleep 、wait、Condition、定时锁等应用, interrupt() 方法是无法中断当前的线程的。所以,shutdownNow() 并不代表线程池就一定立即就能退出,它也可能必须要等待所有正在执行的任务都执行完成了才能退出。但是大多数时候是能立即退出的。
当前线程阻塞,timeout 和 TimeUnit 两个参数,用于设定超时的时间及单位,当前线程阻塞,直到:
然后会监测 ExecutorService 是否已经关闭,返回true(shutdown请求后所有任务执行完毕)或false(已超时)
shutdown()
只是关闭了提交通道,用submit()是无效的;而内部该怎么跑还是怎么跑,跑完再停。shutdownNow()
能立即停止线程池,正在跑的和正在等待的任务都停下了。shutdown()
后,不能再提交新的任务进去;但是 awaitTermination() 后,可以继续提交。awaitTermination()
是阻塞的,返回结果是线程池是否已停止(true/false);shutdown() 不阻塞。RunTime.getRunTime().addShutdownHook()的作用就是在JVM销毁前执行的最后一个线程,通过addShutdownHook添加钩子,当系统执行完这些钩子后,jvm才会关闭,因此我们可以在这个线程中把我们前面使用ExecutorService创建的线程池优雅地关闭掉。
在web3j中异步执行类(Async)中有如下代码:
// 创建线程池
private static final ExecutorService executor = Executors.newCachedThreadPool();
// 添加关闭线程池的钩子
static {
Runtime.getRuntime().addShutdownHook(new Thread(() - > shutdown(executor)));
}
// 关闭线程池的钩子函数
private static void shutdown(ExecutorService executorService) {
// 第一步:使新任务无法提交
executorService.shutdown();
try {
// 第二步:等待未完成任务结束
if(!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
// 第三步:取消当前执行的任务
executorService.shutdownNow();
// 第四步:等待任务取消的响应
if(!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("Thread pool did not terminate");
}
}
} catch(InterruptedException ie) {
// 第五步:出现异常后,重新取消当前执行的任务
executorService.shutdownNow();
Thread.currentThread().interrupt(); // 设置本线程中断状态
}
}
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。