ConcurrentHashMap分析(二)数据扩容

本文详细探讨了ConcurrentHashMap的扩容过程,包括思路、原理及扩容时的并发处理。文章指出,当链表长度超过阈值或数组长度小于某个值时,会触发扩容或转换为红黑树。扩容过程中,ConcurrentHashMap采用并发数据迁移,通过位运算确保索引重计算的均匀分布。文章还分析了链表节点和红黑树节点的迁移方式,展示了其高效的设计策略。

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

前言

在前面的文章ConcurrentHashMap分析(一)整体结构里,我们通过从 ConcurrentHashMap 的整体结构入手,逐步了解了它的数据结构和各个节点的转换关系。这篇文章将讲述 ConcurrenHashMap 的另一个重点:如何在高并发环境下进行扩容,这对我们了解高并发编程思想很有帮助。

由于本人水平有限,分析过程中可能存在纰漏和错误,希望大家可以指出,一起学习,一起进步。

思路

我们在前文查看 ConcurrenHashMap 中发现有一个字段nextTable,它起到在扩容时充当临时存储数组的作用:

/**
 * The next table to use; non-null only while resizing.
 */
private transient volatile Node<K,V>[] nextTable;

既然 ConcurrentHashMap 是采用类似渐进式数据迁移的方式进行扩容,那么对于新旧数组来说,操作多线程就灵活很多了。我们接下来来看下它具体的扩容过程。

在之前分析 putVal 方法时,在后面有一个判断链表阈值的过程,如果链表长度超过一定阈值,就会触发转换为红黑树的操作,具体代码如下:

if (binCount != 0) {
   
    if (binCount >= TREEIFY_THRESHOLD)
        // 链表转换为红黑树
        treeifyBin(tab, i);
    if (oldVal != null)
        return oldVal;
    break;
}

进入treeifyBin后,我们发现其实里面还有一个判断,如果当前存储 hash 槽的数组长度小于MIN_TREEIFY_CAPACITY(64)时,那么只是对原有数组进行扩容2倍的操作。代码如下:

if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
    tryPresize(n << 1);

然后我们来分析tryPersize方法:

private final void tryPresize(int size) {
   
    // 将数组大小扩容为原来的2幂次
    int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
        tableSizeFor(size + (size >>> 1) + 1);
    int sc;
    while ((sc = sizeCtl) >= 0) {
   
        Node<K,V>[] tab = table; int n;
        // 如果原来的数组没有初始化
        if (tab == null || (n = tab.length) == 0) {
   
            n = (sc > c) ? sc : c;
            // 开始初始化数组
            if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
   
                try {
   
                    // 再次判断数组是否需要初始化
                    if (table == tab) {
   
                        // 初始化数组
                        @SuppressWarnings("unchecked")
                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                        table = nt;
                        sc = n - (n >>> 2);
                    }
                } finally {
   
                    sizeCtl = sc;
                }
            }
        }
        // 如果数组已经扩容过了或者容量大小已经大于 MAXIMUM_CAPACITY 了,就直接返回
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值