目录
1、一些基础知识
-1<< 29 的计算过程
Java 中基于 32 位补码进行运算
-1的原码、反码、补码
原码 1 30个0 1
反码 1 30个1 0
补码 1 30个1 1
-1的补码左移 29 位
3 个1 29个0
反码需要减1
110 29 个1
原码(符号位不变,其余位取反)
1 01 29个0 也就是 - (2的29次幂)
对应真值:-536870912
2、Java 线程池的初始化:以 ThreadPoolExecutor 为例
ThreadPoolExecutor 承载了线程池诸多核心逻辑。了解线程池的核心运行逻辑就无法避开这个类。
基础变量 COUNT_BITS、CAPACITY
COUNT_BITS = 29
是所有变量最初始值。它的值为 29
剩余的 CAPACITY、RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED 都是某个基础数字左移 COUNT_BITS 相关的计算,是固定值
CAPACITY 补码形式为 00011111111111111111111111111111
其中 比较重要的参数 CAPACITY 在 32 位补码的形式为 00011111111111111111111111111111
那么和 & CAPACITY 可以用于保留后29位二进制数
~CAPACITY 补码形式为 11100000000000000000000000000000
由上可知, ~CAPACITY 的补码形式为 3个1+29个0 (111 0···0)
那么 & CAPACITY 可以用于保留前3位二进制数
变量 ctl、workerCount、runState
ctl 是一个复合变量
ctl 是一个32位二进制数,它包含两个部分
workerCount、runState。workerCount 用于记录当前线程池运行的线程数,runState 用于记录线程池的状态。
由于 ctl 是一数两用,所以当用它来表示状态时,就无法使用确切值了,而是使用区间,即 ctl 的前3位二进制数+29个0 作为表示状态的基数,后29位二进制数表示有效的线程数,而二者合起来的数字依旧保证状态的不变性。
线程池线程数的理论上限 = (2的30次幂-1)
由于 RUNNING 11100000000000000000000000000000 -536870912 是一个负数,所以有效线程数增加的时候,RUNNING 会越来越小,但是我们也可以在这里推测出线程池理论的上限为 29个1= (2的30次幂-1)=1 073 741 823
实际上限
CAPACITY-1= 29个1 -1 = (2的30次幂-1)-1=1 073 741 822
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
ctl 的初始化 —— ctlOf(re,wc) 方法
//RUNNING | 0 => RUNNING => 11100000000000000000000000000000 => -536870912
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//rs|wc ,当其中一个为0时,返回值就是另一个值
private static int ctlOf(int rs, int wc) { return rs | wc; }
ctl 的初始值= RUNNING = ~CAPACITY = 11100000000000000000000000000000 = -536870912
从上面的分析可以得到,
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0))
=>
ctl = RUNNING | 0 =>
ctl = RUNNING =>
ctl = 11100000000000000000000000000000 =>
ctl = -536870912
线程池有效线程数 workerCount(ctl):ctl的后29位
这个方法的入参是 ctl ,ctl 的后29位用于记录有效线程数
// c & CAPACITY => c & 00011111111111111111111111111111 => 3个0+c的后29位二进制
private static int workerCountOf(int c) { return c & CAPACITY; }
线程池运行状态 runState
源码
runState 以高3位进行区间分类
private static final int COUNT_BITS = Integer.SIZE - 3;//29
private static final int CAPACITY = (1 << COUNT_BITS) - 1;//(1<<29)-1=536870911
private static final int RUNNING = -1 << COUNT_BITS;//(-1<<29)=-536870912
private static final int SHUTDOWN = 0 << COUNT_BITS;//(0<<29)=0
private static final int STOP = 1 << COUNT_BITS;// (1<<29)=536870912
private static final int TIDYING = 2 << COUNT_BITS;//(2<<29)=1073741824
private static final int TERMINATED = 3 << COUNT_BITS;//(3<<29)=1610612736
线程池状态 runState 的区间值
变量名 32位二进制补码 真值
CAPACITY 00011111111111111111111111111111 536870911
~CAPACITY 11100000000000000000000000000000 -536870912
RUNNING 11100000000000000000000000000000 -536870912
SHUTDOWN 00000000000000000000000000000000 0
STOP 00100000000000000000000000000000 536870912
TIDYING 01000000000000000000000000000000 1073741824
TERMINATED 01100000000000000000000000000000 1610612736
- 从数值上可以看出 runState 分布的区间
~CAPACITY(-536870912) =RUNNING(-536870912)
<
SHUTDOWN(0)
<
CAPACITY(536870911)
<
STOP(536870912)
<
TIDYING(1073741824)
<
TERMINATED(1610612736)
获取 runState 各区间 二进制值 的代码
public static void main(String[] args) {
int CAPACITY = (1 << 29) - 1;
int RUNNING = -1 << 29;
int SHUTDOWN = 0 << 29;
int STOP = 1 << 29;
int TIDYING = 2 << 29;
int TERMINATED = 3 << 29;
System.out.println("CAPACITY " + fullLengthTo32(CAPACITY) + " " + CAPACITY);
System.out.println("~CAPACITY " + fullLengthTo32(~CAPACITY) + " " + ~CAPACITY);
System.out.println("RUNNING " + fullLengthTo32(RUNNING) + " " + RUNNING);
System.out.println("SHUTDOWN " + fullLengthTo32(SHUTDOWN) + " " + SHUTDOWN);
System.out.println("STOP " + fullLengthTo32(STOP) + " " + STOP);
System.out.println("TIDYING " + fullLengthTo32(TIDYING) + " " + TIDYING);
System.out.println("TERMINATED " + fullLengthTo32(TERMINATED) + " " + TERMINATED);
}
//Java Integer.toBinaryString 打印字符串,二进制补码默认为 32位,如果数字为负数则正好打印32位,如果为正数,则会以第一个1开始打印,如果为0就是0
//所以这里提供一个小工具方法,可以统一将二进制32位补码打印出来
private static String fullLengthTo32(int arg) {
String str = Integer.toBinaryString(arg);
int gap = 32 - str.length();
StringBuilder result = new StringBuilder();
for (int i = 0; i < gap; i++) {
result.append("0");
}
return result.append(str).toString();
}
线程池运行状态 runStateOf 方法:ctl 的前3位二进制 + 29个0
// c & ~CAPACITY => c & 11100000000000000000000000000000 => c 保留前3位二进制 + 29个0
private static int runStateOf(int c) { return c & ~CAPACITY; }
线程池是否在运行 isRunning
RUNNING 是几个状态中唯一小于0的,并且,由于 ctl 值是一个以前三位表示线程池运行状态的值,所以实际线程池运行期间 ctl 的值会 <= RUNNING ,但是肯定是负数,所以 runstate < SHUTDOWN=0 时,即表示线程池处于运行状态.
RUNNING(-536870912) < SHUTDOWN(0)
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
ThreadPoolExecutor 中的基础方法
runStateLessThan(c,s) 方法
c 小于 s
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
runStateAtLeast(c,s) 方法
c 大于等于 s
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}