ConcurrentHashMap的sizeCtl含义纠正

本文纠正了关于ConcurrentHashMap的sizeCtl变量的常见误解,指出sizeCtl的值不是简单的-N表示有N-1个线程在扩容,而是通过位运算与低16位相关。通过分析源码中的initTable、addCount、tryPresize、transfer、helpTransfer等方法,证明sizeCtl更新后始终为一个小于0的负数,其低16位表示实际扩容线程数。

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

引言:
本文基于JDK1.8版本,而且对ConcurrentHashMap有一定了解的人,本文并非科普该类的用法,而是针对sizeCtl的含义做出纠正

科普文章推荐:
深入浅出ConcurrentHashMap1.8

sizeCtl定义及注释

  /**
     * Table initialization and resizing control.  When negative, the
     * table is being initialized or resized: -1 for initialization,
     * else -(1 + the number of active resizing threads).  Otherwise,
     * when table is null, holds the initial table size to use upon
     * creation, or 0 for default. After initialization, holds the
     * next element count value upon which to resize the table.
     */
    private transient volatile int sizeCtl;

sizeCtl 无可置疑是ConcurrentHashMap中一个重要的变量,在各种资料上能看到的基本就是

sizeCtl :默认为0,用来控制table的初始化和扩容操作
-1 代表table正在初始化
-N 表示有N-1个线程正在进行扩容操作
其余情况:
1、如果table未初始化,表示table需要初始化的大小。
2、如果table初始化完成,表示table的容量,默认是table大小的0.75倍

这些资料其实就是按照注释翻译了一遍,但其实注释是有错误的。
-N 表示有N-1个线程正在进行扩容操作这句话是错误的

这里-N的定义是有问题的,应该取-N对应的二进制的低16位数值为M,此时有M-1个线程进行扩容。
(感谢评论区的朋友指教)

证明:
能修改sizeCtl的方法有五个:

  1. initTable()
  2. addCount()
  3. tryPresize()
  4. transfer()
  5. helpTransfer()

其中initTable是设为-1保证只初始化一次,而且初始化后,把sizeCtl设为长度的0.75倍,此时sizeCtl为正值。

而能把sizeCtl设置为-N的方法只有addCount跟tryPresize方法,而且两个方法的实现逻辑是很相似的,这里选用tryPresize作为讲解。

..省略部分代码
        while ((sc = sizeCtl) >= 0) {
   
            ConcurrentHashMap.Node<K,V>[] tab = table; int n;
            if (tab == null || (n = tab.length) == 0) {
   
                //表为空,初始化表
                // 逻辑和initTable一样,完成后sc也是0.75倍的长度,为正数,继续循环
                // 此处省略代码
            }
            //扩容大小没有达到阈值,或者超过最大容量,无法扩容,直接结束
            else if (c <= sc || n >= MAXIMUM_CAPACITY)
                break;
            else if (tab == table) {
   
                int rs = resizeStamp(n);
                //满足while循环条件,证明sc肯定>=0,所以一开始肯定不会满足该判断,而是执行else代码
                // 这里的意义其实是已经有线程在进行扩容
                if (sc < 0) {
   
                    ConcurrentHashMap.Node<K,V>[] nt;
                    if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                            sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                            transferIndex <= 0)
                        break;
                    if (U.compareAndSwapInt(this, SIZECTL, sc
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值