ExecutorService的shutdownNow方法注意事项
当通过shutdownNow来强行关闭ExecutorService时,它会尝试取消正在执行的任务并返回所有已提交但尚未开始的任务;注意:调用shutdownNow在关闭过程中只会返回尚未开始的任务,而不会返回正在执行的任务。然而,我们无法通过常规方法来找出哪些任务已经开始但尚未结束。这意味着我们无法在关闭过程中知道正在执行的任务的状态,除非任务本身会执行某种检查。
public class Test {public static void main(String[] args) {ExecutorService service = Executors.newFixedThreadPool(3);for (int i = 0; i < 100; i++) {final int finalI = i;service.execute(new Runnable() {@Override public void run() {//...... System.out.println(finalI);}});}// 返回已提交但尚未开始的任务集合 List<Runnable> list = service.shutdownNow();System.out.println(list.toString());} }
以上执行一次结果:
可见返回的任务集合,每个元素concurrent.Test$1@443b7951就是一个任务,其中concurrent为我的包名,Test为类名
由于不能返回正在执行而被中断的任务,所以这也可以说是shutdownNow的局限性,如果不自定义对这些被遗漏的任务进行处理,那么将是糟糕的的代码。日常应该使用shutdown方法来正常关闭;如果非要使用shutdownNow,可以在ExecutorService中跟踪关闭之后被取消的任务:
public class TrackingExecutor extends AbstractExecutorService{private final ExecutorService service;private final Set<Runnable> tasksCancelledAtShutdown= Collections.synchronizedSet(new HashSet<Runnable>());TrackingExecutor(ExecutorService service){this.service=service;}public List<Runnable> getCancelledTasks(){if(!service.isTerminated()){throw new IllegalStateException("");}return new ArrayList<>(tasksCancelledAtShutdown);}@Override public void execute(final Runnable command) {service.execute(new Runnable() {@Override public void run() {try {command.run();}finally {if (isShutdown()&&Thread.currentThread().isInterrupted()){ System.out.println("被打断了"+command); tasksCancelledAtShutdown.add(command);}}}});}@Override public void shutdown() {// 将ExecutorService的其他方法委托给service service.shutdown();}@Override public List<Runnable> shutdownNow() {// 将ExecutorService的其他方法委托给service return service.shutdownNow();}@Override public boolean isShutdown() {// 将ExecutorService的其他方法委托给service return service.isShutdown();}@Override public boolean isTerminated() {// 将ExecutorService的其他方法委托给service return service.isTerminated();}@Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {// 将ExecutorService的其他方法委托给service return service.awaitTermination(timeout,unit);} }
以上程序中,在任务执行过程中,如果调用了shutdownNow方法,那么此时isShutdown为true,并且此时如果任务没有执行完毕,那么将会被打断,我们要将这个任务放到一个特殊的集合,以便后续处理。
我们将上面的Test案例用TrackingExecutor测试一下
public class Test {private volatile TrackingExecutor executor;public synchronized void start() {executor = new TrackingExecutor(Executors.newFixedThreadPool(3));for (int i = 0; i < 5; i++) {final int finalI = i;executor.execute(new Runnable() {@Override public void run() {//...... System.out.println(finalI);}});}}public synchronized void stop() throws InterruptedException {try {System.out.println("已提交尚未开始= " + (executor.shutdownNow()));if (executor.awaitTermination(1000, TimeUnit.MILLISECONDS)) {System.out.println("正在运行而被取消= " + executor.getCancelledTasks());}} finally {executor = null;}}public static void main(String[] args) throws InterruptedException {Test test = new Test();test.start();test.stop();} }
运行一次的结果:
由于shutdownNow方法本来就会返回已提交尚未执行的任务集合,而上面收集的是正在运行而被打断的任务集合,这样两种状态的集合我们都拿到了,就可以做后续的处理了,常见的应用案例是网页爬虫,网页爬虫程序的工作通常是无穷尽的,因此当爬虫程序必须关闭时,我们通常希望保存它的状态,以便稍后重新启动(例如当爬虫程序关闭时,无论是还没有开始的任务,还是那些被取消的任务,都将记录他们的URL,因此当爬虫程序重新启动时,就可以将这些url的页面抓取任务加入到任务队列中)。
参考《Java并发编程实战》
ExecutorService的shutdownNow方法注意事项相关推荐
- ExecutorService shutdown()和shutdownNow()方法区别
ExecutorService是我们经常使用的线程池,当我们使用完线程池后,需要关闭线程池.ExecutorService的shutdown()和shutdownNow()方法都可以用来关闭线程池,那 ...
- 关于线程池ExecutorService的shutdown()与shutdownNow()方法的区别
2019独角兽企业重金招聘Python工程师标准>>> 问题 这两天被一个问题折腾着:一个线程池,可能会有上万个任务要执行.问题是,一旦最先运行的线程执行完,整个线程池就结束了,哪怕 ...
- jQuery中append、insertBefore、after与insertAfter方法注意事项
jQuery中append.appendTo.prepend.prependTo.before.insertBefore.after与insertAfter方法注意事项 这里列的是针对初学jQuery ...
- pthread-win32库编译及使用方法注意事项
"该文引用自 CruiseYoung的:pthread-win32库编译及使用方法注意事项 http://blog.csdn.net/fksec/article/details/415179 ...
- 探究ExecutorService的invokeAll()方法获取的结果是否具有顺序性
探究invokeAll()方法 个人粗糙的主页 该博客源码存放于 github 背景:在用ExecutorService做了一个多线程查询数据并导出之后,对它的invokeAll()方法产生了一个想法 ...
- java bookkeeping_Java - ExecutorService shutdown系列方法 的理解
涉及的主要方法 void shutdown(); List shutdownNow(); boolean awaitTermination(long timeout, TimeUnit unit) t ...
- ExecutorService的submit()方法
ExecutorService总共有三个submit方法: Future<?> submit(Runnable task); <T> Future<T> submi ...
- 如何解析域名,域名A记录解析方法注意事项
常用的域名的解析方法有两种,一种是[A记录解析],另一种是[CNAME别名解析],下面小编就来跟大家说一下a记录解析的方法.另外CNAME别名解析方法可参考下面这篇经验: A记录解析和CNAME别名解 ...
- shutdown、shutdownNow方法的理解
shutdown() 1.当线程池调用该方法时,线程池的状态则立刻变成SHUTDOWN状态.此时,则不能再往线程池中添加任何任务,否则将会抛出RejectedExecutionException异常. ...
最新文章
- Leetcode236 最近公共祖先-二叉树两次遍历
- zeekooper集群搭建_How to do - ZooKeeper集群搭建(我见过最详细的完整教学)
- 问题 | 解决Intel MKL FATAL ERROR: Cannot load mkl_intel_thread.dll 问题(pycharm+Tensorflow)
- Device eth0 does not seem to be present,delaying initialization.
- LeetCode 142环形链表||-中等
- 一本通例题-生日蛋糕——题解超强深搜剪枝,从无限到有限
- SpringBoot之Filter过滤器的实现及排序问题
- 线程创建方式3-实现 callable接口(Java)
- python爬虫实例100例-Python爬虫 实例
- python网络爬虫程序_Python写的网络爬虫程序(很简单)
- Word 2007 目录生成技巧
- 【DIOCP-DEMO说明】所有演示DEMO的简要说明
- JavaScript制作简易的《飞机大战》
- 《高性能MySQL》读书笔记
- 数字电路基础-逻辑门电路
- 微盟致远OA聚水潭YonSuite系统对接集成整体解决方案
- 电池SOC仿真系列-基于粒子群算法电池参数辨识
- 一道智商测试题 月薪三万
- Chapter 6-Blurring Things Up之Using Alpha Channel
- Linux防火墙firewalld安全设置