ThreadPoolExecutor(六)——线程池关闭之后
上一篇主要从代码角度介绍了线程池关闭相关的方法,包括各个方法之间的逻辑关系,调用关系和产生的效果。
这一篇更多从逻辑角度上来说一下线程池在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(六)——线程池关闭之后相关推荐
- ThreadPoolExecutor(五)——线程池关闭相关操作
补充了和Thread的interrupt操作相关的知识,回头再来看ThreadPoolExecutor中interrupt,关闭线程池等相关操作. 1.shutdown /*** Initiates ...
- Java并发基础(六) - 线程池
Java并发基础(六) - 线程池 1. 概述 这里讲一下Java并发编程的线程池的原理及其实现 2. 线程池的基本用法 2.1 线程池的处理流程图 该图来自<Java并发编程的艺术>: ...
- Java队列、线程池及ThreadPoolExecutor自定义线程池实现
目录 1.阻塞队列 2.队列分类 3.API使用 4.线程池 4.1.线程池参数 4.2.线程池实现 4.3.任务执行流程 4.4.拒绝策略 4.5.参数合理值设置 5.自定义线程池流程 6.自定义线 ...
- 【Java 并发编程】线程池机制 ( 线程池阻塞队列 | 线程池拒绝策略 | 使用 ThreadPoolExecutor 自定义线程池参数 )
文章目录 一.线程池阻塞队列 二.拒绝策略 三.使用 ThreadPoolExecutor 自定义线程池参数 一.线程池阻塞队列 线程池阻塞队列是线程池创建的第 555 个参数 : BlockingQ ...
- Executors线程池关闭时间计算
Executors线程池关闭时间计算 学习了:http://blog.csdn.net/wo541075754/article/details/51564359 https://www.cnblogs ...
- Java多线程(三):使用ThreadPoolExecutor创建线程池
文章目录 1. 简介 2. 构造函数说明 3. ThreadPoolExecutor例子 4. 拒绝策略 4.1 CallerRunsPolicy 4.2 AbortPolicy 4.3 Discar ...
- ThreadPoolExecutor – Java线程池示例
Java thread pool manages the pool of worker threads. It contains a queue that keeps tasks waiting to ...
- threadpoolexecutor创建线程池_线程池ThreadPoolExecutor源码分析
什么是线程池 创建线程要花费昂贵的资源和时间,如果任务来了才创建那么响应时间会变长,而且一个进程能创建的线程数量有限.为了避免这些问题,在程序启动的时候就创建若干线程来响应出来,它们被称为线程池,里面 ...
- JUC系列(六) 线程池
最新文章
- 高并发应用场景下的负载均衡与故障转移实践,AgileEAS.NET SOA 负载均衡介绍与实践...
- 简单的字幕效果html,7种HTML5 Figure图片字幕标题特效
- numpy.absolute详解
- linux less命令简介
- GNU C 、ANSI C、标准C、标准c++区别和联系
- SQL大赛——5X5方格棋盘难题
- 域对抗网络Domain adversarial neural network及其应用相关论文
- lc滤波器是利用电感的感抗_“电感”的作用与使用方法
- nand flash与烧录器
- spring源码解析专栏导航
- 计算机组成原理:MIPS
- python爬虫爬取豆瓣电影为啥内容有缺失-Python爬虫之抓取豆瓣影评数据
- 简单的卷积神经网络编程,python卷积神经网络训练
- 分析计算机网络的功能,分析计算机网络管理系统的功能及实现
- Restoring Backups Created Using Older Versions of RMAN
- K8S 部署 skywalking
- 2023年3月华为认证HCIP新增题库(考试编号H12-821)
- 阿里起诉淘宝假货店主,携手数家公司利用大数据打假
- 微信公众平台开发订阅号
- MySQL数据库管理工具Navicat与PhpMyAdmin功能对比
热门文章
- ch341a编程和ttl刷机区别_USB转TTL(CH341A)的注意事项及说明 -
- 黑鲨helo支持html吗,黑鲨2和黑鲨helo区别买哪个好
- 漫画趣解Linux内核
- 关于Android Studio单元测试中“Method d in android.util.Log not mocked.”问题的解决。
- 微信中禁止网页下拉出现网页由XXX提供
- 伦敦 quant_伦敦统一用户组11
- 2021-07-15 声音一些基本概念
- 使用python将pdf转化为长图片
- Mockito开发指南
- 养生年龄的早龄化一一朱乐睿教授