在阅读Java线程池ThreadPoolExecutor源码的时候,发现它很巧妙地把线程池状态runState和线程数workCount两个变量存放在了一个int型变量里面。
我们先看一个数值,如下是一个32位int的二进制:
0010 0000 0000 0000 0000 0000 0000 0001
1)高位第一位表示符号,0是正数,1是负数
2)高位第二位和第三位表示runState的绝对值(线程池运行状态),runState可取值(-1,0,1,2,3)分别表示(running,shutdown,stop,tidying,terminated)
3)剩下的用来表示线程数workCount,这里表示仅有1个线程,总共可以存储2^29-1个线程,大概5亿个。
如何存储在一个变量?
这样的表示法,把状态和workCount存储在了一个int变量里,那么这个变量是怎么计算出来的呢?
首先,我们先获得runState的值,比如:
int runState = -1
再把runState向左移位29位
-1 << 29
这样就得到了
1010 0000 0000 0000 0000 0000 0000 0000
假设现在有3个线程,那么workCount = 3,我们把上面得到得值再加上workCount,即按位或( | )运算,如下
1010 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0011 --------------------------------------- 1010 0000 0000 0000 0000 0000 0000 0011
上面,我们把runState和workCount存储在一个变量里,接下来我们看看如何把他们拆解开。
如何取到runState?
上面我们得到了一个变量
1010 0000 0000 0000 0000 0000 0000 0011
我们知道32位的二进制中,高位前三位其实就是runState,所以我们去除后面29位的值即可。我们只需要做一个按位与( & )运算
1010 0000 0000 0000 0000 0000 0000 0011
1110 0000 0000 0000 0000 0000 0000 0000
---------------------------------------
1010 0000 0000 0000 0000 0000 0000 0000
只需要把结果向右移位29位即可得到runState的值(ThreadPoolExecutor的runState是已经移位以后的值,与本文不同)
如何取到workCount?
后29位就是workCount的值,所以我们去除前3位的值即可。同样我们做一个按位与( & )运算
1010 0000 0000 0000 0000 0000 0000 0011
0001 1111 1111 1111 1111 1111 1111 1111
---------------------------------------
0000 0000 0000 0000 0000 0000 0000 0011