线程池源码-伟大而渺小的ctl
最近看到有些博客提到线程池需要掌握的问题清单,发现自己很多地方是是一知半解的状态,正好借此机会,带着问题去回顾了一波 Java 线程池的源码。
ctl 为何物?
线程池的运作过程对状态的检查非常严格,几乎是走两步一个检查,检查线程池的状态,有效线程的数目,而它们都是基于一个整型变量来实现的,它的「身子」也许很单薄,但是肩上的责任重大。
// 本质是 Integer 型变量,进行了原子性的封装 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
一饰两角
大家可能会想,一个变量怎么能够同时表示两个状态,我当时也非常疑惑,这里就要提到一个巧妙的设计——高低位表示法(名字是我瞎掰的)。
1.紧随在 ctl 变量后面被初始化的两个变量
private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPACITY = (1 << COUNT_BITS) - 1;
COUNT_BITS 的值为 29(整型 32 位);
CAPACITY = 1 << 29 表示将 1 往左移动了 29 位,换算之后就是 1 * 2 的 29 次方,高 3 位被空出来了,而低 29 位用来表示 CAPACITY 即线程池的最大线程容量
1 0000 0000 0000 0001 1 << 29 - 1 0001 1111 1111 1111
2.高 3 位用来表示状态,因为有 5 种状态,需要 3 位表示
private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS;
状态通过数字大小区分,最小的是 RUNNING 状态,最大的是 TERMINATED 状态,一个预示着开始,一个代表结束,逐渐递增,会经过很多中间状态,状态间的转换后面的文章会详细说明。
3.通过 ctl 怎么取得具体状态呢?我们说的高 3 位表示法又是怎么实现的呢?这就要依赖于之前计算好的 CAPACITY 变量。
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 0001 1111 1111 1111 二进制表示
来看看线程池获取状态的方法代码,参数 c 是 ctl 变量当前的值。
private static int runStateOf(int c) { return c & ~CAPACITY; }
首先对 CAPACITY 进行「取反」操作。
0001 1111 1111 1111 ~ 操作符取反,可以看到低 29 位都变成了 0 1110 0000 0000 0000
ctl 和取反后的 CAPACITY 进行 & 运算,熟悉 & 运算的都知道,1 & 1 = 1;1 & 0 = 0,运算之后,ctl 低 29 位都会被置为 0,通过这个方法来屏蔽掉低 29 位的数值干扰。
4.获取有效线程数量也同理,高 3 位的数值被屏蔽掉
private static int workerCountOf(int c) { return c & CAPACITY; }
经过一顿分析,我们得知线程池就是通过以上骚操作来实现 ctl 一饰两角的「表演」。
所以在阅读线程池源码的过程中,不要惊讶为什么通过一个 ctl 即能够获取线程数量,又能得知线程池状态。另外还会频繁出现类似以下条件表达式,rs 表示的是当前线程状态。
rs >= SHUTDOWN rs >= STOP
因为从 RUNNING 到 TERMINATED 状态间的取值是单调递增的,所以可以通过此方法来进行条件判定。
希望看完这篇文章,能够帮助你更流畅地阅读 Java 线程池源码,干就完事了!
- 点赞
- 收藏
- 分享
- 文章举报
- 【图灵学院10】高并发之java线程池源码分析
- 吃透线程池源码
- 线程池ThreadPoolExecutor源码解析
- java线程池架构原理和源码解析(ThreadPoolExecutor)
- 线程池源码-线程池状态
- Java线程池架构原理和源码解析(ThreadPoolExecutor)
- jdk1.8源码探究-线程池-ThreadPoolExecutor-shutdown
- memcached源码分析之线程池机制(二)
- Skynet 源码学习 -- 二级消息队列,Worker 工作线程池, Monitor 。
- 线程池我修正的源码 MFC
- 理解ThreadPoolExecutor源码(一)线程池的corePoolSize、maximumPoolSize和poolSize
- Java 多线程(五)—— 线程池基础 之 FutureTask源码解析
- Java线程池源码及原理
- Python线程池ThreadPoolExecutor源码分析
- ThreadPoolExecutor线程池源码解读
- JUC源码分析27-线程池-FutureTask
- 线程池源码解析
- 源码分析Dubbo网络通讯篇之NettyServer网络事件之线程池
- 线程池源码-任务执行