游乐游手机版
首页/业界动态/文章详情

ConcurrentHashMap 源码解析(JDK8)高并发哈希表的终极实现

时间:2026-04-15 13:59
一、先一句话抓住核心(JDK7 vs JDK8) 要深入理解JDK8 ConcurrentHashMap的精妙设计,必须从其演进历程入手。 在JDK7中,其核心设计是“分段锁”(Segment Locking):将整个哈希表划分为多个独立的Segment,每个Segment独立加锁。这种设计虽然比H

一、先一句话抓住核心(JDK7 vs JDK8)

要深入理解JDK8 ConcurrentHashMap的精妙设计,必须从其演进历程入手。

在JDK7中,其核心设计是“分段锁”(Segment Locking):将整个哈希表划分为多个独立的Segment,每个Segment独立加锁。这种设计虽然比Hashtable的全局锁粒度更细,提升了部分并发能力,但锁的粒度依然是Segment级别,并发度受限于Segment数量,在高并发场景下仍有瓶颈。

JDK8的设计理念发生了革命性转变:数据结构回归经典的数组+链表/红黑树组合;锁机制则升级为CAS无锁算法配合synchronized锁定单个哈希桶(桶的头节点)。锁的粒度被极致细化至单个桶。这一改变带来了并发性能的质的飞跃。

因此,核心总结是:JDK8 ConcurrentHashMap彻底摒弃了分段锁,采用更先进的桶级别锁与无锁CAS操作相结合的设计,是真正为现代高并发应用而生的数据结构。

二、JDK8 ConcurrentHashMap 核心结构

深入源码,其核心数据结构清晰而高效:

public class ConcurrentHashMap {
    // 核心哈希表数组,volatile保证引用可见性
    transient volatile Node[] table;
    // 链表转换为红黑树的阈值
    static final int TREEIFY_THRESHOLD = 8;
    // 红黑树退化为链表的阈值
    static final int UNTREEIFY_THRESHOLD = 6;
    // 允许进行树化的最小表容量
    static final int MIN_TREEIFY_CAPACITY = 64;
    // 核心控制变量,控制初始化、扩容与计数
    transient volatile int sizeCtl;
}

三、核心 Node 节点(JDK8 真实结构)

底层存储单元Node节点的定义,是支撑高并发读写的基础:

static class Node implements Map.Entry {
    final int hash;
    final K key;
    volatile V val;
    volatile Node next;
    // ...
}

这里有三个至关重要的设计要点:

首先,table数组本身被volatile关键字修饰,这确保了数组引用本身的可见性,任何线程都能立即感知到数组的扩容或重建。

其次,Node节点中的val(值)和next(下一个节点引用)也被声明为volatile,这为完全无锁的读操作奠定了内存语义基础。

最后,sizeCtl这个变量是整个ConcurrentHashMap的“控制中枢”。它身兼多职:既是表初始化的控制标志,又是扩容的触发阈值和协调器。透彻理解sizeCtl,就掌握了ConcurrentHashMap并发逻辑的核心。

四、核心流程:put 方法源码(最精简准确版)

理论结合实践,下面这个精简的putVal流程,涵盖了所有关键并发场景:

final V putVal(K key, V value, boolean onlyIfAbsent) {
    if (key == null || value == null)
        throw new NullPointerException();
    int hash = spread(key.hashCode());
    int binCount = 0;
    for (Node[] tab = table;;) {
        Node f; int n, i, fh;
        // 场景1:表未初始化 → 执行初始化
        if (tab == null || (n = tab.length) == 0)
            tab = initTable();
        // 场景2:目标桶为空 → 尝试CAS无锁插入
        else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
            if (casTabAt(tab, i, null, new Node<>(hash, key, value, null)))
                break;
        }
        // 场景3:桶头节点为特殊标记(MOVED)→ 正在扩容,协助扩容
        else if ((fh = f.hash) == MOVED)
            tab = helpTransfer(tab, f);
        // 场景4:发生哈希冲突 → 锁住桶头节点进行处理
        else {
            V oldVal = null;
            synchronized (f) { // 锁粒度仅为当前桶!
                if (tabAt(tab, i) == f) {
                    if (fh >= 0) {
                        // 在链表中插入或更新
                    } else {
                        // 在红黑树中插入或更新
                    }
                }
            }
        }
    }
    addCount(1L, binCount);
    return oldVal;
}

掌握此流程,足以应对大部分面试提问。它主要执行以下几步:

第一步,参数校验。key和value均不允许为null,这是保证并发环境下语义清晰性的铁律。

第二步,计算哈希。通过spread方法对键的hashCode进行二次扰动,使哈希分布更均匀,减少冲突。

第三步,进入自旋主循环。处理四个核心分支:若数组未初始化,则进行初始化;若目标桶为空,则使用CAS操作无锁插入新节点,这是性能最优路径;若检测到桶头节点为特殊转发节点(MOVED),说明正处于扩容阶段,当前线程会协助进行数据迁移;若发生常规哈希冲突,则使用synchronized锁住该桶的头节点,然后在链表或红黑树中执行插入或更新操作。

第四步,后续处理。成功插入后,通过addCount增加元素计数,并检查是否触发扩容。若链表长度达到阈值(8)且表容量达到最小树化容量(64),则将链表转换为红黑树以优化查询性能。

五、为什么 JDK8 这么强?

分析完核心流程,其强大之处可归纳为以下四点:

锁粒度极致细化。 仅锁定发生冲突的单个哈希桶,其他桶的读写操作完全不受影响,并行度达到理论最高。

无冲突则无锁。 在大多数情况下(桶为空),直接使用CAS操作完成插入,性能开销与HashMap几乎无异。

多线程协同扩容。 这是JDK8设计的精髓。扩容时,数据迁移任务被拆分为多个小任务(桶区间),允许多个线程并发参与迁移工作,极大提升了扩容效率,避免了长时间阻塞。

自适应数据结构。 根据冲突程度,在链表和红黑树之间自动转换。在遭遇极端哈希冲突或攻击时,能将操作时间复杂度从O(n)降至O(log n),保障了性能下限。

六、必须搞懂的关键细节(面试高频)

掌握宏观设计后,以下细节是区分“了解”与“精通”的关键。

1. 为什么 key 和 value 不能为 null?

HashMap允许存储null键和null值,但ConcurrentHashMap明确禁止。根本原因在于并发语义的清晰性:在并发环境中,如果允许null值,当调用get(key)返回null时,无法区分是该key不存在,还是该key对应的value本身就是null。这种二义性会破坏线程安全的约定,因此采取最严格策略,禁止null。

2. get 方法真・完全无锁

这是ConcurrentHashMap读性能极高的根本。get操作全程无需任何锁。其安全性依赖于volatile的内存可见性保证:table引用、Node的valnext均为volatile。只要写操作遵循规则更新这些volatile变量,读线程就能安全地看到最新结果。tabAt方法保证了读取桶头节点的原子性。

3. sizeCtl 的 4 种含义(超级高频)

此变量是理解整个Map并发控制的总开关,其值代表四种不同状态:

等于 -1:表示哈希表正在初始化中。

小于 -1:表示正在扩容。其数值的低位记录着正在参与扩容的线程数量。

等于 0:表示创建时未指定初始容量,将使用默认容量。

大于 0:这是最常见状态,表示下一次触发扩容的阈值(当前容量 * 负载因子,默认为0.75)。

4. 为什么链表长度 ≥8 才树化?

这个阈值基于严格的概率统计(泊松分布)。在理想的哈希函数下,单个桶中链表长度达到8的概率极低(约为千万分之六)。如果达到此长度,极有可能遇到了哈希碰撞攻击,或是hashCode实现质量极差。此时将链表转为红黑树,是为了在极端情况下将操作复杂度从O(n)降为O(log n),保障性能。

5. 树化必须满足两个条件

链表长度≥8仅是必要条件之一。另一个条件是当前哈希表的容量必须达到MIN_TREEIFY_CAPACITY(默认64)。如果表容量还很小,优先选择扩容(resize)来分散节点,而不是立即树化。因为扩容能从根源上减少冲突,而树化会引入额外的内存和性能开销。

6. 扩容机制(JDK8 灵魂)

扩容是ConcurrentHashMap并发设计的集中体现。触发条件是元素数量达到阈值(sizeCtl)。新容量为旧容量的两倍。迁移过程采用“分而治之”策略:将旧数组划分为多个迁移区间(stride),每个线程负责迁移一个区间内的桶。迁移过程中,已处理桶的头节点会被替换为一个特殊的ForwardingNode(其hash值为MOVED),其他线程在读写时遇到此标记,会主动加入协助迁移。直至所有数据迁移完成,才会将引用指向新table。整个过程高效、协同,避免了单线程扩容的瓶颈。

7. size () 是弱一致性

size()方法返回的数值不是实时精确值。因为CHM并未为了获取一个绝对准确的计数而全局加锁,那样代价过高。它是通过累加各个分段计数单元(CounterCell)的值来估算的。因此,在高并发场景下,它提供的是一个弱一致性的视图。若业务仅需大致数量,size()完全适用;若强依赖精确计数,则需考虑其他方案。官方推荐使用mappingCount()方法,它返回long类型,更不易溢出。

七、JDK7 vs JDK8 一张表总结

(此处保留原文结构,内容已整合至第一部分“先一句话抓住核心”)

八、总结(可直接背)

总而言之,JDK8的ConcurrentHashMap通过一系列精妙绝伦的设计,实现了业界领先的高并发性能:它摒弃了分段锁,采用数组+链表/红黑树的基础结构;读操作完全无锁,写操作在无冲突时使用CAS,有冲突时仅锁住单个桶;扩容过程支持多线程协同工作,极大提升了效率。同时,通过禁止null键值保证了并发语义的清晰性,通过弱一致性的size()优先保障了性能。

因此,在高并发场景下的选择非常明确:首选ConcurrentHashMap。而传统的HashMap(非线程安全)或Hashtable(性能低下)已不在考虑之列。其设计思想,堪称Java并发编程与数据结构结合的典范之作。

来源:https://www.51cto.com/article/840678.html
上一篇7999 → 5090 元国补新低:iPhone Air 直降 12 期免息,换新低至 4290 元 下一篇踩过无数坑才懂:Linux cat less 和 more 的区别,新手再也不用分页退出难
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
长安汽车明年一季度发布首款车载人形机器人小安
业界动态 · 2026-06-29

长安汽车明年一季度发布首款车载人形机器人小安

长安汽车公布机器人战略,采用“1+N+X”布局,联合头部伙伴攻克大脑、能源、驱动技术。人形机器人“小安”身高169cm,体重69kg,移动速度0 8m s,具备40个自由度,续航超2小时。预计明年一季度发布首款车载组件机器人,已在广州车展展示。

中国信科刷新光通信世界纪录 每秒可下载1.4万部4K电影
业界动态 · 2026-06-29

中国信科刷新光通信世界纪录 每秒可下载1.4万部4K电影

3月25日,光通信领域迎来又一个里程碑:中国信科集团光通信技术和网络全国重点实验室联合鹏城实验室、烽火藤仓光纤科技有限公司,成功实现了2 5Pb s 24芯光纤超大容量实时光传输,再次刷新了世界纪录。 这一研究成果不仅入选国际顶级光通信会议OFC(2026)并荣获“高分论文”称号,还受国际权威SCI

美国调查18万辆特斯拉Model3车门应急释放装置易找性
业界动态 · 2026-06-29

美国调查18万辆特斯拉Model3车门应急释放装置易找性

美国国家公路交通安全管理局对约17 9万辆2024款特斯拉Model3启动缺陷调查,焦点在于车门应急释放装置是否不易找到且标识不清。该调查源于一份缺陷请愿,不意味着立即召回,但可能引发后续监管措施。

doc个人图书馆停服 创始人称无偿转让失败
业界动态 · 2026-06-29

doc个人图书馆停服 创始人称无偿转让失败

运营长达20年,累计服务8000万用户的360doc个人图书馆,最终还是迎来了谢幕时刻。2026年5月1日,这个承载着无数用户收藏记忆的知名平台将正式停止服务——关停原因并非用户流失,而是始终未能寻得一位能够安全接管的合适人选。 创始人蔡智在告别信中坦言,近两个月来,他一直在尝试将360doc无偿转

年Q1随身WiFi实测安全靠谱高性价比机型推荐
业界动态 · 2026-06-29

年Q1随身WiFi实测安全靠谱高性价比机型推荐

2025年10月,艾瑞咨询正式授予飞猫“AI WiFi品类开创者”认证,紧接着CIC也将其认定为“多网融合自由切换技术服务首创者”。这些权威认证背后,折射出一个清晰的市场趋势:移动办公、户外出行、宿舍上网等场景的需求正在快速增长,随身WiFi几乎已成为不少用户的刚需装备。但问题也随之而来——网络卡顿