线程池:ThreadPoolExcutor源码阅读

ThreadPoolExcutor源码流程图:(图片较大,下载再看比较方便)

 

 

线程池里的二进制奥秘

前言:

线程池的五种状态stateRUNNINGSHUTDOWNSTOPTIDYINGTERMINATED)和线程池的工作线程数:workerCount,

这两个变量,可有通过一个变量ctl转成二进制后而获得。

直接看线程池ThreadPoolExecutor源码里,管理状态和工作线程数的代码

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
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; }
private static int ctlOf(int rs, int wc) { return rs | wc; }

 

Integer.sizeInteger类型最大值的二进制的位数:32(位),COUNT_BITS = 29(位),为啥是要要减去3,拿个29呢,因为它想用二进制高3位来表示线程池的状态(state),后面的29位用来表示工作线程数量(workerCount)。

 

比如RUNNINGZ状态是 -1左移29位,即:

-1的二进制算法,先取绝对值1的二进制:00000000 00000000 00000001,再取反码:11111111 11111111 11111110

再取补码(加1):11111111 11111111 11111111 ,这就是-1的二进制表示。

左移运算:-1<<29 = 11100000 00000000 00000000 (左移29, 移动多少位, 后面补多少个0, 高于32位的去掉)。

各个state

-1<<29 = 11100000 00000000 00000000   =>  RUNNINGZ

0<< 29 = 00000000 00000000 00000000   =>  SHUTDOWN

1 <<29 = 00100000 00000000 00000000   =>  STOP

2 <<29 = 01000000 00000000 00000000   =>  TIDYING

3 <<29 = 01100000 00000000 00000000   =>  TERMINATED

线程池就是这样用高三位来表示不同的状态。

所以状态还有这样的关系: RUNNINGZ  <  SHUTDOWN  <  STOP  <  TIDYING  <  TERMINATED

不管各个状态低29位是啥,这个关系都不会变。

 

再看CAPACITY = (1<<29) -1

00100000 00000000 00000000 - 1 =  00011111 11111111 11111111 ,这是线程池最大容量线程数(536870911),

即是用129位可表示线程的数量,那么,ctl = state.3+ 29位,如:

ctl = 11111111 11111111 11111111,表示线程池是RUNNINGZ状态,且线程数为536870911

ctl = 00000000 00000000 00000001,表示线程池是SHUTDOWN状态,且线程数为1

CAPACITY=536870911,表示线程池最大线程数容量为536870911,但这个最大数值可以忽略,

因为在实例化线程池的时候,已经通过传参数设置了核心线程数、允许最大线程数。

 

初始化为 ctl =  new AtomicInteger(ctlOf(RUNNING, 0));

ctlOf(RUNNING, 0)参数中的0,意思是初始化线程池的线程数为0。然后通过ctlOf做或运算,即:

11100000 00000000 00000000 | 00000000 00000000 00000000 = 11100000 00000000 00000000

运算后的结果,把表示状态的高3位、表示线程数的低29位组合起来得到一个数ctl

下次拿到ctl之后,就知道此时线程池的状态和线程数量了。

 

1、那么runStateOf(int c)方法具体是怎么知道线程池的状态的?

假设c =  ctl.get() = 00100000 00000000 00000011,表示STOP状态且还有3个线程

CAPACITY = 1<<29- 1 = 00100000 00000000 00000000 - 1 = 00011111 11111111 11111111

为啥要减1呢?因为减1后:

1、把表示状态的高3位给挪留出来了,值又可以表示线程池最大线程数。

2、把表示线程数的低29位变为了1,那 ~CAPACITY = 11100000 00000000 00000000, 所以:

c &~CAPACITY =00100000 00000000 00000011 & 11100000 00000000 00000000 = 00100000 00000000 00000000

结果00100000 00000000 00000000保持c的高3位不变,把c的低29位全变成0,这就是获得线程池是STOP状态

 

2、通过workerCountOf(int c)获取工作线程数,同上理

 

posted @ 2022-06-22 16:36  無名之徒  阅读(115)  评论(0编辑  收藏  举报