上面注释截图来源于 ThreadPoolExecutor 的源码,别懵圈,仔细看差不多都能懂,能够看出线程池的五种状态以及对应的状态流转 。
不知道你能看懂多少,看不懂也没关系,接下来把上面的注释用图呈现给大家 。通过源码中的注释,能够勾勒出如下线程池的状态流转图(好的注释是多么的重要啊,感叹号!) 。

文章插图
源码解读:部分成员变量及方法
/** * ctl 是一个 AtomicInteger 类型的原子对象 。* 其实设计很有意思:ctl 共包括 32 位(高 3 位表示"线程池状态",低 29 位表示"线程池中的线程数量") 。* 个人感觉:线程池状态与线程数量合二为一,用一个变量来表示,来减少锁竞争,提高并发效率 。*/private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));/** 表示线程池线程数的位数:32 - 3 = 29 位 */private static final int COUNT_BITS = Integer.SIZE - 3;/** 表示最大线程容量(000,11111111111111111111111111111)*/private static final int CAPACITY= (1 << COUNT_BITS) - 1;// runState is stored in the high-order bits(运行状态保存在 int 值的高 3 位)/** 111,00000000000000000000000000000 */private static final int RUNNING= -1 << COUNT_BITS;/** 000,00000000000000000000000000000 */private static final int SHUTDOWN=0 << COUNT_BITS;/** 001,00000000000000000000000000000 */private static final int STOP=1 << COUNT_BITS;/** 010,00000000000000000000000000000 */private static final int TIDYING=2 << COUNT_BITS;/** 011,00000000000000000000000000000 */private static final int TERMINATED =3 << COUNT_BITS;// Packing and unpacking ctl/** 获取线程池的运行状态 */private static int runStateOf(int c){ return c & ~CAPACITY; }/** 线程池内有效线程的数量 (workerCount) */private static int workerCountOf(int c){ return c & CAPACITY; }/** 线程池的状态和线程的数量组装,成为 ctl */private static int ctlOf(int rs, int wc) { return rs | wc; }仔细去看上面的代码,注释已经很清晰啦 。重点关注 ctl 变量,这个变量将线程池自身状态和线程数量,融合在这一个变量中,其中高 3 位表示线程池状态,低 29 位表示线程池中的线程数量,这样在多线程环境下更易保证线程池自身状态和线程数量的统一,不得不佩服源代码作者 Doug Lea,可谓是设计甚妙!源码解读:任务提交 submit 方法背后疑问?当调用 submit() 方法,把一个任务提交给线程池去处理的时候,线程池的处理过程是什么样的呢?
通过开篇对 Executor 的家族简介,能够看到 submit() 方法最终会调用 ThreadPoolExecutor 的 execute 方法,走进源码好好看看 execute 方法都做了啥?

文章插图
重点关注源码中的注释(红框圈住部分),若看懂注释,提交任务时线程池对应的处理,也就懂了一半啦(感触:好的编码规范真的好重要,业务开发时,核心代码一定要有注释) 。
若依然很懵逼,一图胜千言,那就继续上图吧 。

文章插图
了解上图的整体流程,再去看看源码就彻悟啦 。
public void execute(Runnable command) {//【Step 0. 如果任务为空则抛出 NPE 异常】if (command == null)throw new NullPointerException();int c = ctl.get();//【Step 1. 判断核心线程是否已满】// 1.1. 判断当前线程数是否已经达到核心线程数的限制if (workerCountOf(c) < corePoolSize) {// 1.2. 如果未达到核心线程数的限制,则会直接添加一个核心线程,并指定首次执行的任务,进行任务处理if (addWorker(command, true))return;// 1.3. 如果添加失败,则刷新线程池的状态和线程的数量对应的变量 ctlc = ctl.get();}//【Step 2. 判断阻塞队列是否已满】// 2.1. 检查线程池是否是运行状态,然后将任务添加到等待队列if (isRunning(c) && workQueue.offer(command)) {// 2.2. 任务成功添加到等待队列,再次刷新 ctlint recheck = ctl.get();// 2.3. 添加任务到等待队列成功后,如果线程池不是运行状态,则将刚添加的任务从队列移除并执行拒绝策略if (! isRunning(recheck) && remove(command))reject(command);// 2.4. 判断当前线程数量,如果线程数量为 0,则添加一个非核心线程,并且不指定首次执行任务else if (workerCountOf(recheck) == 0)addWorker(null, false);}//【Step 3. 判断最大线程数量是否已经达到】// 3.1. 添加非核心线程,指定首次执行任务,如果添加失败,执行异常策略else if (!addWorker(command, false))reject(command);}结合注释去读代码,应该都能搞懂 。很显然 execute 方法中,多处都调用了 addWorker 方法,接下来简单剖析一下 addWorker 方法 。
推荐阅读
- AI人工智能:JAVA教你拍照识别文字 并语音播报
- JAVA程序员常用的几个工具类
- JAVA并发-AtomicInteger
- Java正则表达式详解
- 美团对 Java 新一代垃圾回收器 ZGC 的探索与实践
- java中的装箱和拆箱
- 2019年的6个JavaScript用户认证库
- 又一个小而美的Java Web框架:Solon
- 万字详文:Java内存泄漏、性能优化、宕机死锁的N种姿势
- 笔记本电池保养方法
