状态管理
线程池使用了一个整型同时保存了状态以及容量等信息, 对于状态的判断,使用了位运算。而在我们日常的Java开发中,位运算使用的比较少(大家更常用的可能是定义枚举值),所以这一块的理解可能会麻烦一些,有C语言基础的同学看起来会简单许多。相关代码如下:
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
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;
对应到二进制其值分别是:
1110 0000 0000 0000 0000 0000 0000 RUNNING
0000 0000 0000 0000 0000 0000 0000 SHUTDOWN
0010 0000 0000 0000 0000 0000 0000 STOP
0100 0000 0000 0000 0000 0000 0000 TIDYING
0110 0000 0000 0000 0000 0000 0000 TERMINATED
0001 1111 1111 1111 1111 1111 1111 CAPACITY
1110 0000 0000 0000 0000 0000 0000 ~CAPACITY
其中获取状态的方法为
private static int runStateOf(int c) { return c & ~CAPACITY; }
位运算的具体规则请自行学习。总之这里在获取状态时,将除了高三位的其他位,全部置为0了,只保留了高三位的值。因此状态可以简化为:
111 RUNNING (十进制7)
000 SHUTDOWN (十进制0)
001 STOP (十进制1)
010 TIDYING (十进制2)
011 TERMINATED (十进制3)
这里我们抛出一个问题,如何判断线程池是否为运行状态呢?第一时间我会想到
private static boolean isRunning(int c) {
return runStateOf(c) == RUNNING;
}
而这里JDK中设计的非常巧妙,只用了一次运算:
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
简单解释下,除RUNNING以外,其他几个状态最高位均为0,这就意味着,作为有符号数,RUNNING是负数 (无论线程池内有多少条线程,溢出情况不考虑,溢出时可能服务器会先一步崩溃),SHUTDOWN为0,其他几个状态均为正数。
其他几种状态的判断也可以简化为:
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}