前言
翻阅 Java 线程池的源码,可以看到用到了大量的位运算操作,本文来分析下这些位运算是如何计算的,以及最后算出的结果是什么。
正文
阅读之前,必须熟悉一下内容
- & 与运算
- | 或运算
- ~ 取反
- << 左移
- 负数的二进制表示方式(先取对应 正数 的二进制,然后对每一位 取反,最后加 1)
- java 中 位运算的优先级(取反 优先级大于 与运算)
ThreadPoolExecutor 源码
ThreadPoolExecutor 用一个 int 类型来表示当前线程池的 运行状态 和 线程有效数量。
但是不同平台的 int 类型的范围不一样,我们先假定用 32 位的二进制表示 int 类型:(以下内容都是基于这个条件)
-
高 3 位表示 线程池运行状态
-
低 29 位表示 线程有效数量
// 高 3 位 表示线程池状态,低 29 位表示线程个数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 线程个数的表示 位数(上面也提到了不同平台 int 类型范围不一样)
// 不管 int 是多少位, 反正高三位 就是表示线程状态,剩余的位数表示线程数量
private static final int COUNT_BITS = Integer.SIZE - 3;
// 线程最大数量
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 高三位表示 线程池状态
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;
// 获取线程池状态
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 获取线程池有效线程数量
private static int workerCountOf(int c) { return c & CAPACITY; }
// 获取上面提到的 32 位 int 类型的数值
private static int ctlOf(int rs, int wc) { return rs | wc; }
位运算详解
线程池的几个属性
-
COUNT_BITS = Integer.SIZE - 3;
COUNT_BITS 表示用多少二进制位表示 线程数量, 这里假定 Integer.SIZE = 32 (注意: 这里不是 Integer.MAX_VALUE),所以最终结果 COUNT_BITS= 29
-
CAPACITY = (1 << COUNT_BITS) - 1
CAPACITY 表示当前线程池中的最大线程数量,这个位运算可以拆解成 2 步:
CAPACITY = 1 << 29
得到 1 000…0000(29 个 0)CAPACITY = CAPACITY-1
得到 1111…111 (29 个 1)
-
RUNNING = -1 << COUNT_BITS
RUNNING 表示线程池处于 运行状态,COUNT_BITS 上面说到是 29,因此这个位运算就表示 -1 左移 29 位。
-1 如果用 2 进制表示
-
获取 -1 的正数,也就是 1 的二进制: 0000000…00000 1 (前面 31 位 0)
-
对上一步进行取反, 1111111111…1111 0 (前面 31 位 1)
-
对上一步 +1 操作, 111111111…1111 (32 位 1)
因此 - 1 左移 29 位, 就得到了 111 0000…00000 ( 29个 0) 。 高三位 111 表示 RUNNING 状态
-
-
SHUTDOWN = 0 << COUNT_BITS
如此类推, 高三位为 000
-
STOP = 1 << COUNT_BITS
高三位为 001
-
TIDYING = 2 << COUNT_BITS
高三位为 010
-
TERMINATED = 3 << COUNT_BITS
高三位为 011
线程池的几个方法
参数 c 就是一开始提到了 32 位整数
1. runStateOf(int c)
private static int runStateOf(int c)
{
return c & ~CAPACITY;
}
-
~ CAPACITY
CAPACITY 从上面可以得知为 1111…111 (29 bit),取反后就是 111 0000000(29个 0)
-
c & 上面的结果
就可以获取到 高三位,而后 29 位 全部为 0(1 & 0 或者 0 & 0都为 0)
2. workerCountOf(int c)
private static int workerCountOf(int c) {
return c & CAPACITY;
}
CAPACITY 为 000 111111(29个1)
因此 c & CAPACITY, 就可以获取变量 c 的低 29 位的值,高三位 与运算结果 为 0
3. ctlOf(int rs, int wc)
private static int ctlOf(int rs, int wc) {
return rs | wc;
}
rs 为 线程状态, wc 表示 线程数量, 或运算的结果就是,就相当于把 rs 的前三位,和 wc 的后 29 位,像字符串一样拼接 到了一起。
总结
上面提到的那些位运算操作是研究 ThreadPoolExecutor
源码的基础,如果为了省事,也完全不用研究这么透彻, 记住文中开头的源码注释内容即可。
比如 CAPACITY
表示的最到线程数量就是 29 bit 1。