ConcurrentHashMap 原理详解

ConcurrentHashMap(CHM) 是 Java 并发包(JUC)中线程安全的哈希表实现,相比 Hashtable 和 Collections.synchronizedMap,它通过 分段锁(JDK7) 和 CAS + synchronized(JDK8) 实现高并发访问。


1. JDK7 的 ConcurrentHashMap(分段锁)

(1) 数据结构

  • Segment 数组:默认 16 个 Segment(相当于 16 个独立的 HashMap),每个 Segment 继承 ReentrantLock

  • HashEntry 数组:每个 Segment 内部是一个 HashEntry 数组(链表结构)。

(2) 锁机制

  • 分段锁:不同 Segment 互不影响,并发度 = Segment 数量(默认 16)。

  • 写操作:只需锁住目标 Segment,其他 Segment 仍可并发读写。

  • 读操作:无锁,volatile 保证可见性。

(3) 缺点

  • Segment 数量固定:扩容时只扩当前 Segment 的 HashEntry 数组,无法全局扩容。

  • 锁粒度较粗:单个 Segment 锁住整个桶链表。


2. JDK8 的 ConcurrentHashMap(CAS + synchronized)

(1) 数据结构

  • Node 数组:类似 HashMap,使用 Node(链表)和 TreeNode(红黑树)。

  • 并发控制

    • CAS:用于无竞争时的快速插入(如 putVal 中的 tabAt/casTabAt)。

    • synchronized:锁住桶的头节点(粒度更细)。

(2) 核心优化

特性JDK7JDK8
锁粒度Segment(分段锁)桶头节点(synchronized)
数据结构数组 + 链表数组 + 链表 + 红黑树
扩容分段扩容协助扩容(多线程协同)
哈希冲突链表链表或红黑树(阈值=8)

(3) 关键操作

① put 流程
  1. 计算 key 的 hash,定位到桶。

  2. 如果桶为空,CAS 插入头节点。

  3. 如果桶不为空,synchronized 锁住头节点,处理链表或红黑树插入。

  4. 判断是否需要扩容。

② get 流程
  • 无锁,直接访问 volatile 的 Node 数组(保证可见性)。

③ 扩容(transfer)
  • 多线程协助:当前线程扩容时,其他线程若访问到正在迁移的桶,会帮助迁移。

  • 高低位拆分:类似 HashMap,拆分成低位链表和高位链表。


3. JDK8 的线程安全实现

(1) CAS 操作

  • 初始化数组sizeCtl 变量控制,通过 CAS 竞争初始化权。

  • 插入头节点tabAt/casTabAt 保证原子性。

(2) synchronized 锁优化

  • 仅锁住单个桶的头节点,不影响其他桶的并发。

  • 锁升级:无竞争时用 CAS,竞争时用 synchronized

(3) size 计算

  • 基础计数器baseCount(CAS 更新)。

  • 分片计数CounterCell[](避免 CAS 竞争,类似 LongAdder)。


4. 常见面试问题

Q1: ConcurrentHashMap 为什么比 Hashtable 快?

  • Hashtable:全局锁(synchronized 方法级),所有操作串行。

  • ConcurrentHashMap

    • JDK7:分段锁,16 个 Segment 并发。

    • JDK8:桶级锁(synchronized + CAS),并发度更高。

Q2: JDK8 的 CHM 如何解决哈希冲突?

  • 链表长度 ≥8 且数组容量 ≥64 时,转为红黑树(时间复杂度 O(n) → O(log n))。

Q3: CHM 的 size() 是准确的吗?

  • 不绝对准确:由于并发环境下统计的是瞬时值,但实际误差可忽略。


5. 总结

版本实现方式优点缺点
JDK7分段锁(ReentrantLock)减小锁粒度Segment 数量固定
JDK8CAS + synchronized锁粒度更细、支持红黑树、扩容优化实现复杂度高

适用场景

  • 高并发读ConcurrentHashMap 优于 Collections.synchronizedMap

  • 高并发写:JDK8 的 CHM 性能接近无锁结构(如 ConcurrentHashMap vs HashMap + 外部锁)。

理解其原理后,可以更高效地处理并发环境下的键值存储需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值