1.导语

最近在工作中,有遇到下面这样一段代码,某个同事一看到代码中的shutdown(),马上就断定这代码执行不了,我问为什么这么说,他说线程池都关了,这任务怎么执行?不能说没有问题,但事实真如他所说吗,我们来探一探shutdown()的虚实。

简单代码

2.shutdown 源码

shutdown 源码

从shutdown 源码的注释我们可以看到,它会初始化一个顺序的已提交的任务的关闭操作,并且不再接受新的任务;如果线程池已经被showdown了,那么该方法的调用将没有任何的效果了。

下面我来对showdown内部调用的方法做个解析。

checkShutdownAccess

checkShutdownAccess

这个方法其实没什么说的,比较简单,就是对workers的线程做一个安全权限检查。

advanceRunState

advanceRunState

该方法通过cas操作设置runState。如果当前的线程池的状态值大于给定的值,,也即是runStateAtLeast(c, targetState) 返回true ,那么就不做任何操作了,直接break;如果返回false,那么就看ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))) 设置是否成功,否则一直重复这个过程。

interruptIdleWorkers

interruptIdleWorkers

里面有一个interruptIdleWorkers 方法,默认传了false。传false的意思是把,在获取锁的情况下,把workers的线程都执行interrupt()操作。

interruptIdleWorkers

interruptIdleWorkers

注释说明,中断可能正在等待任务的线程(表示没有被锁定)以便他们可以检查终止或配置更改。忽略SecurityExceptions(在这种情况下,某些线程可能会保留不间断)。

如果线程没有被interrupt 并且tryLock到锁了,那么就可以判定这是一个IdleWorkers,将会执行interrupt() 方法。如果worker线程在执行任务,runWorker方法中中执行的Worker是占有锁的,这里也就无法获取到锁,即tryLock不到,就是非IdleWorkers。

tryTerminate

tryTerminate

先看注释,如果线程池状态是shutdown并且线程池和队列是空的,或者线程池是stop状态并且线程池是空的,把他改为terminate状态;如果线程池可以被terminate,但是workerCount 不为0,终止一个dle worker来确保 shutdown 信号传递下去。该方法一定要跟在任何可能会使terminate的操作之后----减少worker count 或在showdow中从队列中移除任务。

if (isRunning(c) ||                runStateAtLeast(c, TIDYING) ||                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))                return;//如果线程池的状态是isRunning,或者状态值>=TIDYING,或者SHUTDOWN并且workQueue不为//空,直接返回
if (workerCountOf(c) != 0) { // Eligible to terminate                interruptIdleWorkers(ONLY_ONE);                return; }//如果workerCountOf 不为0,表示可以被terminate,interruptIdleWorkers(true) 线程后将 //shutdown 信号传递下去。
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {  try {    terminated();  } finally {    ctl.set(ctlOf(TERMINATED, 0));    termination.signalAll();  }  return;}//这里通过cas 将状态设置为TIDYING,如果成功则调用 terminated()方法,执行成功后,最后 将状态//设置为TERMINATED,并唤醒awaitTermination中等待的线程。

实例

ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5, 10, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5));        for (int i = 0; i < 5; i++) {            poolExecutor.submit(new MyTask());        }        poolExecutor.shutdown();try {                //5秒后关闭                poolExecutor.awaitTermination(5, TimeUnit.SECONDS);            } catch (InterruptedException e) {                System.out.println(e.getMessage());            }*/class MyTask implements Runnable {    @Override    public void run() {        try {            System.out.println(Thread.currentThread().getName());            Thread.sleep(3000);        }catch (Exception e) {            System.out.println(e.getMessage());        }    }}

小结

通过以上的一些分析,当然不够全面,还有一些方法没有说明,以及一个demo,我们可以看到线程池关闭都能正确输出结果。线程池关闭的关键就在于一个worker退出后会调用tryTerminate(),将这种信号传递下去,其他的线程才能被依次处理,最终尘归尘,变为 Terminate。

好了,喜欢的朋友点赞+关注+转发,与小编共同成长[奋斗][奋斗][奋斗]

线程池什么时候调用shutdown方法_ThreadPoolExecutor.shutdown()?相关推荐

  1. 暴露的全局方法_面试刷题36:线程池的原理和使用方法?

    线程池原理和使用在面试中被高频问到,比如阿里的面试题.下面我们针对问题来进行回答. 为什么要使用线程池? 线程池的使用场景有2: 1, 高并发场景:比如tomcat的处理机制,内置了线程池处理http ...

  2. Java线程池中submit()和execute()方法有什么区别

    两个方法都可以向线程池提交任务,execute()方法的返回类型是void,它定义在Executor接口中,而submit()方法返回有计算结构的Future对象,它定义在ExecutorServic ...

  3. python 进程池、线程池 与异步调用、回调机制

    进程池.线程池使用案例 from concurrent.futures import ProcessPoolExecutor # 进程池模块 from concurrent.futures impor ...

  4. Java线程池ExecutorService中重要的方法

    ExecutorService 介绍 ExecutorService是java线程池定义的一个接口,它在java.util.concurrent包中,在这个接口中定义了和后台任务执行相关的方法. Ja ...

  5. Java 编程问题:十、并发-线程池、可调用对象和同步器

    原文:Java Coding Problems 协议:CC BY-NC-SA 4.0 贡献者:飞龙 本文来自[ApacheCN Java 译文集],自豪地采用谷歌翻译. 本章包括涉及 Java 并发的 ...

  6. 并发编程---线程queue---进程池线程池---异部调用(回调机制)

    线程 队列:先进先出 堆栈:后进先出 优先级:数字越小优先级越大,越先输出 import queueq = queue.Queue(3) # 先进先出-->队列 q.put('first') q ...

  7. 线程池的submit和execute方法区别

    线程池中的execute方法大家都不陌生,即开启线程执行池中的任务.还有一个方法submit也可以做到,它的功能是提交指定的任务去执行并且返回Future对象,即执行的结果.下面简要介绍一下两者的三个 ...

  8. 如何使用线程池,优雅的调用外部接口,然后将数据一并返回给前端

    当我们接到一个需求的时候,一个接口里面我们需要调用外部一个两个甚至三个以上的接口的时候,我们一般怎么做呢? 请看下图一个列子,一个接口中,我们需要调用两个查询,然后将数据一起汇合返回给前端页面, 旧的 ...

  9. java 线程池 execute_Java线程池的submit和execute方法区别

    线程池中的execute方法大家都不陌生,即开启线程执行池中的任务. 还有一个方法submit也可以做到,它的功能是提交指定的任务去执行并且返回Future对象,即执行的结果. 下面简要介绍一下两者的 ...

最新文章

  1. [图示]话剧《被结婚时代》将剩女分4级
  2. 物流公司借接入平台实现异地仓库信息实时掌握
  3. oracle触发器的类型及使用方法
  4. STL(一)Containers
  5. ElasticSearch查询 第四篇:匹配查询(Match)
  6. 链接ftp命令行_windows下最轻便的FTP/SCP文件管理器
  7. Matlab数据标准化
  8. 第一次更名为OpenInfra的“她”,给我们带来了哪些惊喜?| 技术头条
  9. geforce experience不能登录_青椒第二课堂禁毒平台|官方网站登录
  10. Spyder远程连接矩池云
  11. 你不能访问此文件夹,因为你组织的安全策略阻止了未经身份验证的来宾访问
  12. CI生成查询记录集result(),row(),row_array().....
  13. Microsoft Access 2002中文版标准培训教程pdf
  14. VS2017使用github
  15. 将转为时间戳php,php将时间转化为时间戳的方法
  16. 【Java 8 新特性】Java LocalDate 详解
  17. OVM虚拟化,做Openstack的减法
  18. 七:对微服务配置中心的理解
  19. 嵌入式 - 瑞萨电子的并购交易
  20. 随机森林、LGBM基于贝叶斯优化调参

热门文章

  1. Java教程分享:五分钟了解一致性hash算法
  2. plc梯形图语言c1,plc梯形图编程语言是什么?
  3. opencv进阶学习笔记14:分水岭算法 实现图像分割
  4. 【Python】程序的分支结构之异常处理
  5. VTK:绘制BarChart条形图用法实战
  6. boost::units::quantity相关的测试程序
  7. boost::intrusive_ref_counter相关的测试程序
  8. boost::regex模块在 cpp 文件中搜索类定义,使用全局数据的测试程序
  9. boos::reverse_iterator相关的测试程序
  10. boost::mp11::mp_map_update_q相关用法的测试程序