0.9.3、线程池—— ThreadPoolExecutor 的基础变量 ctl 、 runState 和 workerCount

本文深入剖析了Java线程池的核心实现,特别是ThreadPoolExecutor类中的ctl变量,详细解释了workerCount和runState的二进制位运算,以及线程池状态的判断方法。通过对COUNT_BITS、CAPACITY等常量的理解,揭示了线程池状态的区间分布和线程数的计算方式,帮助读者掌握线程池的底层运行逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、一些基础知识

Java 中的二进制位运算

-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位二进制数,它包含两个部分
workerCountrunState。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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值