本次不讲线程池的运行逻辑,只讲一下线程池中状态的切换和一些其他属性方法
1、状态属性
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;
// 所有的任务都已经终止了,workerCount(有效线程数)为0
private static final int TIDYING = 2 << COUNT_BITS;
// 在terminated()方法执行完成后进入该状态
private static final int TERMINATED = 3 << COUNT_BITS;
1.1、CAPACITY
首先 Integer.SIZE的值是32,即COUNT_BITS的值是29
private static final int COUNT_BITS = 29;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 上面的步骤是1左移29为再减一,结果如下
// 1: 0000 0000 0000 0000 0000 0000 0000 0001
// (1 << 29) : 0010 0000 0000 0000 0000 0000 0000 0000
// (1 << 29)-1: 0001 1111 1111 1111 1111 1111 1111 1111
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
1.2、RUNNING
先求-1的二进制,在左移29位,负数的二进制需要先求反码再求补码
private static final int RUNNING = -1 << COUNT_BITS;
// 先求负一
// 1原码 : 0000 0000 0000 0000 0000 0000 0000 0001
// 反码 : 1111 1111 1111 1111 1111 1111 1111 1110
// -1补码 : 1111 1111 1111 1111 1111 1111 1111 1111
// -1 << 29 : 1110 0000 0000 0000 0000 0000 0000 0000
1.3、SHUTDOWN
先求0的二进制,在左移29位
private static final int SHUTDOWN = 0 << COUNT_BITS;
// 0原码: 0000 0000 0000 0000 0000 0000 0000 0000
// 0 << 29 : 0000 0000 0000 0000 0000 0000 0000 0000
1.4、STOP
先求1的二进制,在左移29位
private static final int STOP = 1 << COUNT_BITS;
// 1原码 : 0000 0000 0000 0000 0000 0000 0000 0001
// 1 << 29 : 0010 0000 0000 0000 0000 0000 0000 0000
1.5、TIDYING
先求2的二进制,在左移29位
// 2原码 : 0000 0000 0000 0000 0000 0000 0000 0010
// 2 << 29 : 0100 0000 0000 0000 0000 0000 0000 0000
private static final int TIDYING = 2 << COUNT_BITS;
1.6、结束状态 TERMINATED
先求3的二进制,在左移29位
private static final int TERMINATED = 3 << COUNT_BITS;
// 3原码 : 0000 0000 0000 0000 0000 0000 0000 0011
// 3 << 29 : 0110 0000 0000 0000 0000 0000 0000 0000
RUNNING :1110 0000 0000 0000 0000 0000 0000 0000
SHUTDOWN :0000 0000 0000 0000 0000 0000 0000 0000
STOP :0010 0000 0000 0000 0000 0000 0000 0000
TIDYING :0100 0000 0000 0000 0000 0000 0000 0000
TERMINATED :0110 0000 0000 0000 0000 0000 0000 0000
所有的状态只用到了最高3位
2、主要方法
2.1、获取运行状态-runStateOf
~:二进制按位取反
&:二进制计算只要有一个为0就是0
// 比如c=1110 0000 0000 0000 0000 0000 0000 0001; c & ~CAPACITY
// CAPACITY: 0001 1111 1111 1111 1111 1111 1111 1111
// ~CAPACITY : 1110 0000 0000 0000 0000 0000 0000 0000
// c: 1110 0000 0000 0000 0000 0000 0000 0001
// c & ~CAPACITY: 1110 0000 0000 0000 0000 0000 0000 0000
private static int runStateOf(int c) { return c & ~CAPACITY; }
这里的做法说白了就是让后面的29位全部失效,只看高三位
2.2、获取线程数量-workerCountOf
// 比如c=1110 0000 0000 0000 0000 0000 0000 0001; c & CAPACITY
// c: 1110 0000 0000 0000 0000 0000 0000 0001
// CAPACITY: 0001 1111 1111 1111 1111 1111 1111 1111
// c & CAPACITY: 0000 0000 0000 0000 0000 0000 0000 0001
private static int workerCountOf(int c) { return c & CAPACITY; }
这里说白了就是抛弃掉高三位,剩下的29位作为线程池总数
注意:有的地方说线程池最多可以创建Integer.MAX_VALUE个线程,这里是错误的,最多创建0001 1111 1111 1111 1111 1111 1111 1111(即536 870 911)个线程。
详细见addWorker方法
// 线程总数数大于536 870 911
// 如果是创建核心线程,不能大于核心线程数;如果创建非核心线程数则不能大于非核心线程数
// 否则返回false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
2.3、获取ctl-ctlOf
// rs:线程池状态,wc:线程池线程数量
// |:二进制计算只要有一个为1就是1
// 举例子 状态是RUNING 线程数为1
// rs=RUNNING: 1110 0000 0000 0000 0000 0000 0000 0000
// wc =1 : 0000 0000 0000 0000 0000 0000 0000 0001
// rs | wc: 1110 0000 0000 0000 0000 0000 0000 0001
private static int ctlOf(int rs, int wc) { return rs | wc; }
这里就是把线程状态和线程数合并成一个新的二进制数据
3、结束
我第一次看到这里的时候,心里是这么想的:代码写的真好,下次别写了。
这代码挺消耗队友的