上一篇主要从代码角度介绍了线程池关闭相关的方法,包括各个方法之间的逻辑关系,调用关系和产生的效果。

这一篇更多从逻辑角度上来说一下线程池在shutdown之后,原来正常的处理流程有哪些变化,既是总结也是扩展。

shutdown操作之后,首先最重要的一点变化就是线程池状态变成了SHUTDOWN。该状态是开始关闭线程池之后,从RUNNING改变状态经过的第一个状态(还有一种情况是直接进STOP,调用shutdownNow的时候),有个图画的挺好,见博客Java 7之多线程线程池 - 线程池原理(2)

从入口开始看,在这个状态变化之后,每个方法的处理流程和之前比发生了什么变化?

1.execute

public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();if (! isRunning(recheck) && remove(command))reject(command);else if (workerCountOf(recheck) == 0)addWorker(null, false);}else if (!addWorker(command, false))reject(command);}

有以下几种情况:

1.如果现在状态不是RUNNING,说明要么正在SHUTDOWN要么已经SHUTDOWN完毕了,这时isRunning方法是false,会走到最后一个else if中,通过addWorker的状态来执行相应操作。addWorker下一个段落会说。

2.如果现在是RUNNING操作,而且入队列成功了,然后这里需要一个double check,重新检测线程池的状态,如果不是RUNNING,而且remove成功,直接reject任务。如果remove方法失败,什么都不做(因为有其他的方法正在remove任务,比如shoutDownNow的drainQueue,purge,runWorker结束时的processWorkerExit)。

3.如果现在是RUNNING操作,如果offer失败了,说明队列满了,也执行最后一个if else,调用addWorker,这时也可能开启了SHUTDOWN操作。

2.addWorker

// Check if queue empty only if necessary.if (rs >= SHUTDOWN &&! (rs == SHUTDOWN &&firstTask == null &&! workQueue.isEmpty()))return false;

先看这个会返回false的判断,

1.STOP,TIDYING和TERMINATED这三种状态都会直接返回false。

2.如果是SHUTDOWN,而且firstTask不是null,也返回false。

3.如果是SHUTDOWN,firstTask是null,而且任务队列是空,返回false。

现在要看的是SHUTDOWN状态,fistTask是null,任务队列不是空的情况。

addWorker(null, X)这种传参方式,除了初始化线程数的时候,只有processWorkerExit,execute的recheck发现wc个数为0,这两种情况。

关于addWorker传null的含义还有些迷惑,上一篇中也特意有一个段落说这个问题,以后再研究下看看有没有新的理解和发现。

3.getTask

/*** Performs blocking or timed wait for a task, depending on* current configuration settings, or returns null if this worker* must exit because of any of:* 1. There are more than maximumPoolSize workers (due to*    a call to setMaximumPoolSize).* 2. The pool is stopped.* 3. The pool is shutdown and the queue is empty.* 4. This worker timed out waiting for a task, and timed-out*    workers are subject to termination (that is,*    {@code allowCoreThreadTimeOut || workerCount > corePoolSize})*    both before and after the timed wait.** @return task, or null if the worker must exit, in which case*         workerCount is decremented*/private Runnable getTask() {boolean timedOut = false; // Did the last poll() time out?retry:for (;;) {int c = ctl.get();int rs = runStateOf(c);// Check if queue empty only if necessary.if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {decrementWorkerCount();return null;}boolean timed;      // Are workers subject to culling?for (;;) {int wc = workerCountOf(c);timed = allowCoreThreadTimeOut || wc > corePoolSize;if (wc <= maximumPoolSize && ! (timedOut && timed))break;if (compareAndDecrementWorkerCount(c))return null;c = ctl.get();  // Re-read ctlif (runStateOf(c) != rs)continue retry;// else CAS failed due to workerCount change; retry inner loop}try {Runnable r = timed ?workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :workQueue.take();if (r != null)return r;timedOut = true;} catch (InterruptedException retry) {timedOut = false;}}}

先看注释:

在取任务的时候有两种策略,一直阻塞或带超时的等待,取决于线程池的参数设置。返回null如果该Worker由于以下几种情况退出:

1.wc的数量超过了maximumPoolSize了(通常由于)调用了setMaximumPoolSize方法临时减小了maximumPoolSize值,这时返回null来干掉Worker。

2.线程池处于STOP状态。

3.线程池处于SHUTDOWN状态,而且任务队列是空的。

4.Worker在等待任务的时候超时了,而且超时的Worker需要被terminated,条件是allowCoreThreadTimeOut || workerCount > corePoolSize,即当该线程池允许核心线程timeout(无论是max还是core的Worker都会退出)或者当前wc个数已经超过了核心线程数的时候(退出的max线程的Worker),Worker可以退出线程池。

4.runWorker

runWorker中调用了getTask方法,所以其相应执行结果和getTask的返回有关。比如上一个段落中说的那几种情况,线程池在SHUTDOWN状态且任务队列为空,会返回null。线程池在STOP状态也会返回null(不检查队列是否为空,因为STOP状态是shutdownNow引起的,所有task都已经被drainQueue方法移除了)。

而返回null意味着runWorker中的循环会结束,然后调用processWorkerExit方法去做一些Worker退出的相关操作。

ThreadPoolExecutor(六)——线程池关闭之后相关推荐

  1. ThreadPoolExecutor(五)——线程池关闭相关操作

    补充了和Thread的interrupt操作相关的知识,回头再来看ThreadPoolExecutor中interrupt,关闭线程池等相关操作. 1.shutdown /*** Initiates ...

  2. Java并发基础(六) - 线程池

    Java并发基础(六) - 线程池 1. 概述 这里讲一下Java并发编程的线程池的原理及其实现 2. 线程池的基本用法 2.1 线程池的处理流程图 该图来自<Java并发编程的艺术>: ...

  3. Java队列、线程池及ThreadPoolExecutor自定义线程池实现

    目录 1.阻塞队列 2.队列分类 3.API使用 4.线程池 4.1.线程池参数 4.2.线程池实现 4.3.任务执行流程 4.4.拒绝策略 4.5.参数合理值设置 5.自定义线程池流程 6.自定义线 ...

  4. 【Java 并发编程】线程池机制 ( 线程池阻塞队列 | 线程池拒绝策略 | 使用 ThreadPoolExecutor 自定义线程池参数 )

    文章目录 一.线程池阻塞队列 二.拒绝策略 三.使用 ThreadPoolExecutor 自定义线程池参数 一.线程池阻塞队列 线程池阻塞队列是线程池创建的第 555 个参数 : BlockingQ ...

  5. Executors线程池关闭时间计算

    Executors线程池关闭时间计算 学习了:http://blog.csdn.net/wo541075754/article/details/51564359 https://www.cnblogs ...

  6. Java多线程(三):使用ThreadPoolExecutor创建线程池

    文章目录 1. 简介 2. 构造函数说明 3. ThreadPoolExecutor例子 4. 拒绝策略 4.1 CallerRunsPolicy 4.2 AbortPolicy 4.3 Discar ...

  7. ThreadPoolExecutor – Java线程池示例

    Java thread pool manages the pool of worker threads. It contains a queue that keeps tasks waiting to ...

  8. threadpoolexecutor创建线程池_线程池ThreadPoolExecutor源码分析

    什么是线程池 创建线程要花费昂贵的资源和时间,如果任务来了才创建那么响应时间会变长,而且一个进程能创建的线程数量有限.为了避免这些问题,在程序启动的时候就创建若干线程来响应出来,它们被称为线程池,里面 ...

  9. JUC系列(六) 线程池

最新文章

  1. 高并发应用场景下的负载均衡与故障转移实践,AgileEAS.NET SOA 负载均衡介绍与实践...
  2. 简单的字幕效果html,7种HTML5 Figure图片字幕标题特效
  3. numpy.absolute详解
  4. linux less命令简介
  5. GNU C 、ANSI C、标准C、标准c++区别和联系
  6. SQL大赛——5X5方格棋盘难题
  7. 域对抗网络Domain adversarial neural network及其应用相关论文
  8. lc滤波器是利用电感的感抗_“电感”的作用与使用方法
  9. nand flash与烧录器
  10. spring源码解析专栏导航
  11. 计算机组成原理:MIPS
  12. python爬虫爬取豆瓣电影为啥内容有缺失-Python爬虫之抓取豆瓣影评数据
  13. 简单的卷积神经网络编程,python卷积神经网络训练
  14. 分析计算机网络的功能,分析计算机网络管理系统的功能及实现
  15. Restoring Backups Created Using Older Versions of RMAN
  16. K8S 部署 skywalking
  17. 2023年3月华为认证HCIP新增题库(考试编号H12-821)
  18. 阿里起诉淘宝假货店主,携手数家公司利用大数据打假
  19. 微信公众平台开发订阅号
  20. MySQL数据库管理工具Navicat与PhpMyAdmin功能对比

热门文章

  1. ch341a编程和ttl刷机区别_USB转TTL(CH341A)的注意事项及说明 -
  2. 黑鲨helo支持html吗,黑鲨2和黑鲨helo区别买哪个好
  3. 漫画趣解Linux内核
  4. 关于Android Studio单元测试中“Method d in android.util.Log not mocked.”问题的解决。
  5. 微信中禁止网页下拉出现网页由XXX提供
  6. 伦敦 quant_伦敦统一用户组11
  7. 2021-07-15 声音一些基本概念
  8. 使用python将pdf转化为长图片
  9. Mockito开发指南
  10. 养生年龄的早龄化一一朱乐睿教授