当通过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方法注意事项相关推荐

  1. ExecutorService shutdown()和shutdownNow()方法区别

    ExecutorService是我们经常使用的线程池,当我们使用完线程池后,需要关闭线程池.ExecutorService的shutdown()和shutdownNow()方法都可以用来关闭线程池,那 ...

  2. 关于线程池ExecutorService的shutdown()与shutdownNow()方法的区别

    2019独角兽企业重金招聘Python工程师标准>>> 问题 这两天被一个问题折腾着:一个线程池,可能会有上万个任务要执行.问题是,一旦最先运行的线程执行完,整个线程池就结束了,哪怕 ...

  3. jQuery中append、insertBefore、after与insertAfter方法注意事项

    jQuery中append.appendTo.prepend.prependTo.before.insertBefore.after与insertAfter方法注意事项 这里列的是针对初学jQuery ...

  4. pthread-win32库编译及使用方法注意事项

    "该文引用自 CruiseYoung的:pthread-win32库编译及使用方法注意事项 http://blog.csdn.net/fksec/article/details/415179 ...

  5. 探究ExecutorService的invokeAll()方法获取的结果是否具有顺序性

    探究invokeAll()方法 个人粗糙的主页 该博客源码存放于 github 背景:在用ExecutorService做了一个多线程查询数据并导出之后,对它的invokeAll()方法产生了一个想法 ...

  6. java bookkeeping_Java - ExecutorService shutdown系列方法 的理解

    涉及的主要方法 void shutdown(); List shutdownNow(); boolean awaitTermination(long timeout, TimeUnit unit) t ...

  7. ExecutorService的submit()方法

    ExecutorService总共有三个submit方法: Future<?> submit(Runnable task); <T> Future<T> submi ...

  8. 如何解析域名,域名A记录解析方法注意事项

    常用的域名的解析方法有两种,一种是[A记录解析],另一种是[CNAME别名解析],下面小编就来跟大家说一下a记录解析的方法.另外CNAME别名解析方法可参考下面这篇经验: A记录解析和CNAME别名解 ...

  9. shutdown、shutdownNow方法的理解

    shutdown() 1.当线程池调用该方法时,线程池的状态则立刻变成SHUTDOWN状态.此时,则不能再往线程池中添加任何任务,否则将会抛出RejectedExecutionException异常. ...

最新文章

  1. Leetcode236 最近公共祖先-二叉树两次遍历
  2. zeekooper集群搭建_How to do - ZooKeeper集群搭建(我见过最详细的完整教学)
  3. 问题 | 解决Intel MKL FATAL ERROR: Cannot load mkl_intel_thread.dll 问题(pycharm+Tensorflow)
  4. Device eth0 does not seem to be present,delaying initialization.
  5. LeetCode 142环形链表||-中等
  6. 一本通例题-生日蛋糕——题解超强深搜剪枝,从无限到有限
  7. SpringBoot之Filter过滤器的实现及排序问题
  8. 线程创建方式3-实现 callable接口(Java)
  9. python爬虫实例100例-Python爬虫 实例
  10. python网络爬虫程序_Python写的网络爬虫程序(很简单)
  11. Word 2007 目录生成技巧
  12. 【DIOCP-DEMO说明】所有演示DEMO的简要说明
  13. JavaScript制作简易的《飞机大战》
  14. 《高性能MySQL》读书笔记
  15. 数字电路基础-逻辑门电路
  16. 微盟致远OA聚水潭YonSuite系统对接集成整体解决方案
  17. 电池SOC仿真系列-基于粒子群算法电池参数辨识
  18. 一道智商测试题 月薪三万
  19. Chapter 6-Blurring Things Up之Using Alpha Channel
  20. Linux防火墙firewalld安全设置

热门文章

  1. [PyG] 1.如何使用GCN完成一个最基本的训练过程(含GCN实现)
  2. java中jlaber用法_laber的for属性
  3. 给笔记本电脑外接显示器增加副屏
  4. c# sql where in 参数化传值
  5. matlab生成gif动图
  6. 常见的国外主机提供商小结
  7. Fleck说明文档翻译
  8. python爬虫进阶-汽车之家贴吧信息(字体反爬-动态映射)
  9. Windows2003 3389端口修改
  10. 基于Unity的C/S架构数据交互