Concurrent programming - ConcurrentHashMap

foreword

Starting with JDK 1.8, a thread-safe Map, namely ConcurrentHashMap, is provided. The bottom layer uses the method of synchronized + CAS to ensure thread safety while also having certain concurrency performance.

common problem

1. What is the storage structure of ConcurrentHashMap?

It consists of array + linked list + red-black tree. The time complexity of finding an element in a linked list is 0(n), while that of a red-black tree is 0(logn)

2. How does ConcurrentHashMap handle hash conflicts?

Use the chain address method.

3. Why is the expansion factor set to 0.75 and the linked list length threshold is 8?

Follow the Poisson distribution (Poisson Distribution), so that the probability of converting the linked list to a red-black tree becomes very small, and the conversion of the linked list to a red-black tree will cause performance loss.

4. Timing of expanding the Node array (satisfy any one of the following conditions)

If the length of the Node array is <64 and the length of the linked list is >=8, expand the size of the Node array to twice the original length.

When the number of elements inside the ConcurrentHashMap reaches 0.75n (n is the length of the Node array), expand the Node array to twice the original length.

5. Mutual conversion between linked list and red-black tree

If the length of the Node array is >=64 and the length of the linked list is >=8, the linked list is converted into a red-black tree.

If the number of elements inside the red-black tree is <=6, convert the red-black tree into a linked list.

put, putAll methods

put method

public V put(K key, V value) {
    
    
    return putVal(key, value, false);
}

putAll method

public void putAll(Map<? extends K, ? extends V> m) {
    
    
    tryPresize(m.size());
    for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
        putVal(e.getKey(), e.getValue(), false);
}

It can be seen that both the put method and the putAll method will call the putVal method.

putVal method

final V putVal(K key, V value, boolean onlyIfAbsent) {
    
    
  	// 校验key、value非空
    if (key == null || value == null) throw new NullPointerException();
  	// 计算key的哈希值(spread方法 => (h ^ (h >>> 16)) & 0x7fffffff)
  	int hash = spread(key.hashCode());
    int binCount = 0;
    for (Node<K,V>[] tab = table;;) {
    
    
        Node<K,V> f; int n, i, fh;
      	// 如果Node数组还没有初始化
        if (tab == null || (n = tab.length) == 0)
          	// 初始化Node数组
            tab = initTable();
      	// 根据key的哈希值计算数组下标,如果该数组下标的位置还没有元素
        else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
    
    
          	// 构建Node节点,落到Node数组对应下标处
            if (casTabAt(tab, i, null,
                         new Node<K,V>(hash, key, value, null)))
                // 结束循环
                break;                   
        }
      	// 如果Node节点的哈希值等于-1,即当前线程完成了所负责的扩容工作
        else if ((fh = f.hash) == MOVED)
          	// 进行辅助扩容
            tab = helpTransfer(tab, f);
        else {
    
    
            V oldVal = null;
          	// 对指定下标位置的Node节点加锁
            synchronized (f) {
    
    
              	// 如果对应数组下标处的节点仍然是上述的Node节点
                if (tabAt(tab, i) == f) {
    
    
                  	// 针对链表的处理
                    if (fh >= 0) {
    
    
                      	// 使用binCount记录链表的长度
                        binCount = 1;
                        for (Node<K,V> e = f;; ++binCount) {
    
    
                            K ek;
                          	// 如果key的哈希值相同且key也相同
                            if (e.hash == hash &&
                                ((ek = e.key) == key ||
                                 (ek != null && key.equals(ek)))) {
    
    
                                oldVal = e.val;
                              	// 如果onlyIfAbsent参数为false,则使用新值覆盖旧值;反之,不会覆盖旧值
                                if (!onlyIfAbsent)
                                    e.val = value;
                                // 结束循环
                                break;
                            }
                            Node<K,V> pred = e;
                          	// 构建新的Node节点
                            if ((e = e.next) == null) {
    
    
                              	// 加入到链表中
                                pred.next = new Node<K,V>(hash, key,
                                                          value, null);
                                // 结束循环
                              	break;
                            }
                        }
                    }
                  	// 针对红黑树的处理
                    else if (f instanceof TreeBin) {
    
    
                        Node<K,V> p;
                        binCount = 2;
                        if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
                                                       value)) != null) {
    
    
                            oldVal = p.val;
                            if (!onlyIfAbsent)
                                p.val = value;
                        }
                    }
                }
            }
            if (binCount != 0) {
    
    
              	// 如果链表长度大于等于8
                if (binCount >= TREEIFY_THRESHOLD)
                  	// 扩容或者转化为红黑树
                    treeifyBin(tab, i);
              	// 如果存在旧值,则直接返回旧值
                if (oldVal != null)               	
                    return oldVal;
              	// 结束循环
                break;
            }
        }
    }
  	// 主要用于统计元素总个数然后判断是否满足扩容的条件,如果满足进行扩容
    addCount(1L, binCount);
    return null;
}

initTable method

Used to initialize the Node array

private final Node<K,V>[] initTable() {
    
    
    Node<K,V>[] tab; int sc;	
  	// 如果Node数组还未初始化,则一直进行循环
    while ((tab = table) == null || tab.length == 0) {
    
    
        if ((sc = sizeCtl) < 0)
            Thread.yield(); 
        // 使用CAS方式将sizectl属性的值更新为-1,表示Node数组在初始化中
        else if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
    
    
            try {
    
    
              	// 如果Node数组还未初始化
                if ((tab = table) == null || tab.length == 0) {
    
    
                  	// 获取Node数组的初始容量,默认16
                    int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
                    @SuppressWarnings("unchecked")
                  	// 初始化Node数组
                    Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                    table = tab = nt;
                  	// 计算扩容阈值,即0.75*n,默认12
                    sc = n - (n >>> 2);
                }
            } finally {
    
    
              	// 最终将扩容阈值赋值给sizeCtl属性
                sizeCtl = sc;
            }
          	// 结束while循环
            break;
        }
    }
  	// 返回初始化完成的Node数组
    return tab;
}

sizeCtl : greater than or equal to 0 (uninitialized) => -1 (initializing) => 0.75n (initialization completed)

treeifyBin method

If the length of the Node array is greater than or equal to 64 and the length of the linked list is greater than or equal to 8, the linked list is converted into a red-black tree

If the length of the Node array is less than 64 and the length of the linked list is greater than or equal to 8, expand the Node array to twice its original size and perform data migration

private final void treeifyBin(Node<K,V>[] tab, int index) {
    
    
    Node<K,V> b; int n, sc;
    if (tab != null) {
    
    
      	// 如果Node数组长度小于64,则触发扩容
        if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
          	// 对Node数组进行多线程并发扩容,扩容到原长度*2(包括旧数据的迁移)
            tryPresize(n << 1);
      	// 如果Node数组长度大于等于64,则将链表转化成红黑树
        else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {
    
    
            synchronized (b) {
    
    
                if (tabAt(tab, index) == b) {
    
    
                    TreeNode<K,V> hd = null, tl = null;
                    for (Node<K,V> e = b; e != null; e = e.next) {
    
    
                        TreeNode<K,V> p =
                            new TreeNode<K,V>(e.hash, e.key, e.val,
                                              null, null);
                        if ((p.prev = tl) == null)
                            hd = p;
                        else
                            tl.next = p;
                        tl = p;
                    }
                    setTabAt(tab, index, new TreeBin<K,V>(hd));
                }
            }
        }
    }
}

tryPresize method

Expand the Node array and perform data migration

private final void tryPresize(int size) {
    
    
  	// 计算扩容后的容量
  	// MAXIMUM_CAPACITY:1 << 30
  	// tableSizeFor(...):找到大于等于目标值的且最小的2的n次幂
    int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
        tableSizeFor(size + (size >>> 1) + 1);
    int sc;
  	// 如果Node数组处于未扩容的状态,就一直进行循环
    while ((sc = sizeCtl) >= 0) {
    
    
        Node<K,V>[] tab = table; int n;
      	// 如果Node数组未初始化
        if (tab == null || (n = tab.length) == 0) {
    
    
          	// 取初始容量与扩容后的容量两者的最大值
            n = (sc > c) ? sc : c;
          	// 使用CAS操作将sizeCtl属性的值更新为-1,表示处于扩容中的状态
            if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
    
    
                try {
    
    
                    if (table == tab) {
    
    
                        @SuppressWarnings("unchecked")
                      	// 创建新的(即扩容后的)Node数组
                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                      	// 使用新的Node数组替换旧的Node数组
                        table = nt;
                      	// 计算新的扩容阈值
                        sc = n - (n >>> 2);
                    }
                } finally {
    
    
                    sizeCtl = sc;
                }
            }
        }
      	// 如果已经扩容完成或者达到最大容量,则无需进行后续操作直接跳出循环
        else if (c <= sc || n >= MAXIMUM_CAPACITY)
            break;
      	// 处理数据迁移
        else if (tab == table) {
    
    
          	// 计算扩容戳
            int rs = resizeStamp(n);
          	// 如果Node数组在扩容中
            if (sc < 0) {
    
    
                Node<K,V>[] nt;
              	// 判断当前扩容工作是否没有结束,并且当前线程是否有机会参与到扩容工作
              	// 条件一、判断当前线程获取到的扩容戳是否是本次扩容生成的扩容戳(true-不是;false-是)
              	// 条件二、判断当前线程是否需要参与到扩容工作(true-不需要;false-需要)
              	// 条件三、判断当前参与扩容工作的线程数是否达到了最大值(true-是;false-否)
              	// 条件四、通过判断nextTable是否为空,进而判断扩容过程是否已经结束(true-已经结束;false-还未结束)
                if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                    sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                    transferIndex <= 0)
                  	// 跳出循环
                    break;
              	// 如果当前线程成功参与到扩容工作(每增加一个参与扩容的线程,则对sizectl属性在低位加1)
                if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
                  	// 扩容与数据迁移
                    transfer(tab, nt);
            }
          	// 此时Node数组还未扩容,但是Node数组的长度达到了扩容阈值
          	// 对sizectl属性值左移16位,此时高16位表示扩容戳,低16位表示参与扩容的线程的数量
          	// 注意、每增加一个参与扩容的线程,则对sizectl属性在低位加1。并且只有第一次需要加2
            else if (U.compareAndSwapInt(this, SIZECTL, sc,
                                         (rs << RESIZE_STAMP_SHIFT) + 2))
              	// 扩容与数据迁移
                transfer(tab, null);
        }
    }
}

transfer method

Node array expansion and data migration (linked list: the expansion is twice the original; put the nodes that need to be migrated into the high-level linked list, and the nodes that do not need to be migrated into the low-level linked list, and finally these two linked lists are added to the expanded Node array. subscript)

private final void transfer(Node<K,V>[] tab, Node<K,V>[] nextTab) {
    
    
  	// n:扩容前的Node数组的长度
    int n = tab.length, stride;
  	// stride:每个线程负责的扩容范围,通常是16
    if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
        stride = MIN_TRANSFER_STRIDE;
  	// 如果扩容后的Node数组还没有初始化
    if (nextTab == null) {
    
               
        try {
    
    
            @SuppressWarnings("unchecked")
          	// 初始化扩容后的Node数组,长度扩容为原来的2倍
            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
            nextTab = nt;
        } catch (Throwable ex) {
    
          
            sizeCtl = Integer.MAX_VALUE;
            return;
        }
        nextTable = nextTab;
      	// 第一次记录扩容前的Node数组的长度
        transferIndex = n;
    }
  	// 记录扩容后的Node数组的长度
    int nextn = nextTab.length;
  	// 用于标记数据迁移完成的节点
    ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
    boolean advance = true;
  	// 标记数据迁移是否完成
    boolean finishing = false; 
    for (int i = 0, bound = 0;;) {
    
    
        Node<K,V> f; int fh;
        while (advance) {
    
    
            int nextIndex, nextBound;
            if (--i >= bound || finishing)
                advance = false;
          	// 将transferIndex属性赋值到nextIndex
            else if ((nextIndex = transferIndex) <= 0) {
    
    
                i = -1;
                advance = false;
            }
          	// 比如扩容前Node数组的长度为32,则第一次循环得到的范围为[16, 31],然后第二次的范围为[0, 15],使用nextBound、i分别记录左起点、右起点
            else if (U.compareAndSwapInt
                     (this, TRANSFERINDEX, nextIndex,
                      nextBound = (nextIndex > stride ?
                                   nextIndex - stride : 0))) {
    
    
                bound = nextBound;
                i = nextIndex - 1;
                advance = false;
            }
        }
        if (i < 0 || i >= n || i + n >= nextn) {
    
    
            int sc;
            if (finishing) {
    
    
                nextTable = null;
                table = nextTab;
                sizeCtl = (n << 1) - (n >>> 1);
                return;
            }
          	// 对参与扩容的线程数减一
            if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, sc - 1)) {
    
    
                if ((sc - 2) != resizeStamp(n) << RESIZE_STAMP_SHIFT)
                    return;
                finishing = advance = true;
                i = n; 
            }
        }
      	// 如果指定下标的Node节点为空(也就是不需要数据迁移),使用CAS方式更新为ForwardingNode节点,即数据迁移完成
        else if ((f = tabAt(tab, i)) == null)
            advance = casTabAt(tab, i, null, fwd);
      	// 如果节点的哈希值为-1,则表示该节点为ForwardingNode节点,即数据迁移完成
        else if ((fh = f.hash) == MOVED)
          	// 标记可以进行下一次的区间遍历
            advance = true; 
        else {
    
    
          	// 对当前需要进行数据迁移的Node节点加锁
            synchronized (f) {
    
    
              	// 校验Node数组下标为i的节点是否发生变化
                if (tabAt(tab, i) == f) {
    
    
                    Node<K,V> ln, hn;
                  	// 如果是链表
                    if (fh >= 0) {
    
    
                        int runBit = fh & n;
                        Node<K,V> lastRun = f;
                      	// 从当前Node节点的后继节点开始,沿着链表向后遍历
                        for (Node<K,V> p = f.next; p != null; p = p.next) {
    
    
                            int b = p.hash & n;
                            if (b != runBit) {
    
    
                              	// 更新runBit
                                runBit = b;
                              	// 更新lastRun
                                lastRun = p;
                            }
                        }
                        if (runBit == 0) {
    
    
                            ln = lastRun;
                            hn = null;
                        }
                        else {
    
    
                            hn = lastRun;
                            ln = null;
                        }
                      	// 从当前Node节点开始,沿着链表向后遍历
                        for (Node<K,V> p = f; p != lastRun; p = p.next) {
    
    
                            int ph = p.hash; K pk = p.key; V pv = p.val;
                          	// 如果该节点不需要迁移,则将该节点使用头插法加入到低位链表
                            if ((ph & n) == 0)
                                ln = new Node<K,V>(ph, pk, pv, ln);
                          	// 如果该节点需要迁移,则将该节点使用头插法加入到高位链表
                            else
                                hn = new Node<K,V>(ph, pk, pv, hn);
                        }
                      	// 将低位链表加入到扩容后的Node数组的指定下标处
                        setTabAt(nextTab, i, ln);
                      	// 将高位链表加入到扩容后的Node数组的指定下标处
                        setTabAt(nextTab, i + n, hn);
                      	// 标记指定下标
                        setTabAt(tab, i, fwd);
                      	// 标记可以进行下一次的区间遍历
                        advance = true;
                    }
                  	// 如果是红黑树
                    else if (f instanceof TreeBin) {
    
    
                        TreeBin<K,V> t = (TreeBin<K,V>)f;
                        TreeNode<K,V> lo = null, loTail = null;
                        TreeNode<K,V> hi = null, hiTail = null;
                        int lc = 0, hc = 0;
                        for (Node<K,V> e = t.first; e != null; e = e.next) {
    
    
                            int h = e.hash;
                            TreeNode<K,V> p = new TreeNode<K,V>
                                (h, e.key, e.val, null, null);
                            if ((h & n) == 0) {
    
    
                                if ((p.prev = loTail) == null)
                                    lo = p;
                                else
                                    loTail.next = p;
                                loTail = p;
                                ++lc;
                            }
                            else {
    
    
                                if ((p.prev = hiTail) == null)
                                    hi = p;
                                else
                                    hiTail.next = p;
                                hiTail = p;
                                ++hc;
                            }
                        }
                        ln = (lc <= UNTREEIFY_THRESHOLD) ? untreeify(lo) :
                            (hc != 0) ? new TreeBin<K,V>(lo) : t;
                        hn = (hc <= UNTREEIFY_THRESHOLD) ? untreeify(hi) :
                            (lc != 0) ? new TreeBin<K,V>(hi) : t;
                        setTabAt(nextTab, i, ln);
                        setTabAt(nextTab, i + n, hn);
                        setTabAt(tab, i, fwd);
                        advance = true;
                    }
                }
            }
        }
    }
}

addCount method

insert image description here

private final void addCount(long x, int check) {
    
    
    CounterCell[] as; long b, s;
  	// 如果CounterCell数组已经初始化,或者CAS操作更新元素个数失败(说明存在多个线程竞争)
    if ((as = counterCells) != null ||
        !U.compareAndSwapLong(this, BASECOUNT, b = baseCount, s = b + x)) {
    
    
        CounterCell a; long v; int m;
        boolean uncontended = true;
      	// 条件一与二、判断CounterCell数组是否未初始化
      	// 条件三、判断CounterCell数组指定下标元素是否为空
      	// 条件四、判断CAS操作是否更新CounterCell的value失败
        if (as == null || (m = as.length - 1) < 0 ||
            (a = as[ThreadLocalRandom.getProbe() & m]) == null ||
            !(uncontended =
              U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))) {
    
    
          	// 初始化CounterCell数组,可能会对CounterCell数组进行扩容
            fullAddCount(x, uncontended);
            return;
        }
        if (check <= 1)
            return;
      	// 计算当前的元素个数
        s = sumCount();
    }
    if (check >= 0) {
    
    
        Node<K,V>[] tab, nt; int n, sc;
      	// sizeCtl 如果为负数,表示正在扩容中;如果为正数,表示一个扩容阈值
      	// 条件1、Node数组在扩容中或者满足了Node数组扩容的条件
      	// 条件2、Node数组非空
      	// 条件3、Node数组的元素个数 < (1 << 30)
        while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
               (n = tab.length) < MAXIMUM_CAPACITY) {
    
    
          	// 计算扩容戳
            int rs = resizeStamp(n);
          	// 如果Node数组在扩容中
            if (sc < 0) {
    
    
              	// 判断当前扩容工作是否没有结束,并且当前线程是否有机会参与到扩容工作
              	// 条件一、判断当前线程获取到的扩容戳是否是本次扩容生成的扩容戳(true-不是;false-是)
              	// 条件二、判断当前线程是否需要参与到扩容工作(true-不需要;false-需要)
              	// 条件三、判断当前参与扩容工作的线程数是否达到了最大值(true-是;false-否)
              	// 条件四、通过判断nextTable是否为空,进而判断扩容过程是否已经结束(true-已经结束;false-还未结束)
                if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                    sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||
                    transferIndex <= 0)
                    break;
              	// 如果当前线程成功参与到扩容工作(每增加一个参与扩容的线程,则对sizectl属性在低位加1)
                if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))
                  	// 扩容与数据迁移
                    transfer(tab, nt);
            }
          	// 此时Node数组还未扩容,但是Node数组的长度达到了扩容阈值
          	// 对sizectl属性值左移16位,此时高16位表示扩容戳,低16位表示参与扩容的线程的数量
          	// 注意、每增加一个参与扩容的线程,则对sizectl属性在低位加1。并且只有第一次需要加2
            else if (U.compareAndSwapInt(this, SIZECTL, sc,
                                         (rs << RESIZE_STAMP_SHIFT) + 2))
              	// 扩容与数据迁移
                transfer(tab, null);
          	// 计算当前的元素个数
            s = sumCount();
        }
    }
}

fullAndCount method

private final void fullAddCount(long x, boolean wasUncontended) {
    
    
    int h;
    if ((h = ThreadLocalRandom.getProbe()) == 0) {
    
    
        ThreadLocalRandom.localInit();      
        h = ThreadLocalRandom.getProbe();
        wasUncontended = true;
    }
    boolean collide = false;                
    for (;;) {
    
    
        CounterCell[] as; CounterCell a; int n; long v;
      	// 如果CounterCell数组已经初始化
        if ((as = counterCells) != null && (n = as.length) > 0) {
    
    
          	// 如果CounterCell数组指定下标的元素为空
            if ((a = as[(n - 1) & h]) == null) {
    
    
                if (cellsBusy == 0) {
    
    
                  	// 初始化CounterCell
                    CounterCell r = new CounterCell(x); 
                    if (cellsBusy == 0 &&
                        U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
    
    
                        boolean created = false;
                        try {
    
                   
                            CounterCell[] rs; int m, j;
                          	// 再次判断如果CounterCell数组已经初始化,并且CounterCell数组指定下标的元素为空
                            if ((rs = counterCells) != null &&
                                (m = rs.length) > 0 &&
                                rs[j = (m - 1) & h] == null) {
    
    
                              	// 将上述的CounterCell添加到CounterCell数组指定下标处
                                rs[j] = r;
                                created = true;
                            }
                        } finally {
    
    
                            cellsBusy = 0;
                        }
                      	// 如果上述操作成功,则结束循环
                        if (created)
                            break;
                      	// 如果上述操作失败,则重试
                        continue;           
                    }
                }
                collide = false;
            }
            else if (!wasUncontended)       
                wasUncontended = true;      
          	// 如果使用CAS方式对CounterCell更新value值成功,则结束循环
            else if (U.compareAndSwapLong(a, CELLVALUE, v = a.value, v + x))
                break;
            else if (counterCells != as || n >= NCPU)
                collide = false;            
            else if (!collide)
                collide = true;
          	// 对CounterCell数组进行扩容
            else if (cellsBusy == 0 &&
                     U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
    
    
                try {
    
    
                    if (counterCells == as) {
    
    
                      	// 对CounterCell数组扩容为原来的2倍
                        CounterCell[] rs = new CounterCell[n << 1];
                        for (int i = 0; i < n; ++i)
                            rs[i] = as[i];
                        counterCells = rs;
                    }
                } finally {
    
    
                    cellsBusy = 0;
                }
                collide = false;
                continue;                   
            }
            h = ThreadLocalRandom.advanceProbe(h);
        }
      	// 对CounterCell数组进行初始化
        else if (cellsBusy == 0 && counterCells == as &&
                 U.compareAndSwapInt(this, CELLSBUSY, 0, 1)) {
    
    
            boolean init = false;
            try {
    
                               
                if (counterCells == as) {
    
    
                  	// 初始化CounterCell数组
                    CounterCell[] rs = new CounterCell[2];
                  	// 初始化指定下标处的CounterCell元素
                    rs[h & 1] = new CounterCell(x);
                    counterCells = rs;
                    init = true;
                }
            } finally {
    
    
                cellsBusy = 0;
            }
          	// 如果上述操作成功,则结束循环
            if (init)
                break;
        }
      	// 如果使用CAS方式对基础值更新成功,则结束循环
        else if (U.compareAndSwapLong(this, BASECOUNT, v = baseCount, v + x))
            break;                          
    }
}

sumCount method

Accumulate and sum each element of the CounterCell array. Combined with the context, it is to get the number of elements.

final long sumCount() {
    
    
    CounterCell[] as = counterCells; CounterCell a;
    long sum = baseCount;
    if (as != null) {
    
    
        for (int i = 0; i < as.length; ++i) {
    
    
            if ((a = as[i]) != null)
                sum += a.value;
        }
    }
    return sum;
}

helpTransfer method

If the expansion work that the current thread is responsible for has been completed, it will help other threads to complete the expansion work.

final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {
    
    
    Node<K,V>[] nextTab; int sc;
  	// 如果Node数组非空,并且当前节点是ForwardingNode类型的节点,即所负责的扩容工作已经完成
  	// 并且nextTab非空,即表示扩容工作还未完成
    if (tab != null && (f instanceof ForwardingNode) &&
        (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
    
    
      	// 计算扩容戳
        int rs = resizeStamp(tab.length);
      	// 如果处于扩容中的状态
        while (nextTab == nextTable && table == tab &&
               (sc = sizeCtl) < 0) {
    
    
          	// 判断当前扩容工作是否没有结束,并且当前线程是否有机会参与到扩容工作
          	// 条件一、判断当前线程获取到的扩容戳是否是本次扩容生成的扩容戳(true-不是;false-是)
          	// 条件二、判断当前线程是否需要参与到扩容工作(true-不需要;false-需要)
          	// 条件三、判断当前参与扩容工作的线程数是否达到了最大值(true-是;false-否)
            if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||
                sc == rs + MAX_RESIZERS || transferIndex <= 0)
              	// 结束循环
                break;
          	// 如果当前线程成功参与到扩容工作(每增加一个参与扩容的线程,则对sizectl属性在低位加1)
            if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {
    
    
              	// 扩容与数据迁移
                transfer(tab, nextTab);
              	// 结束循环
                break;
            }
        }
        return nextTab;
    }
    return table;
}

size method

public int size() {
    
    
  	// 使用sumCount方法计算元素个数
    long n = sumCount();
  	// 元素个数最大值为Integer类型的最大值,即2147483647
    return ((n < 0L) ? 0 :
            (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE :
            (int)n);
}

Guess you like

Origin blog.csdn.net/qq_34561892/article/details/129475331