ConcurrentHashMap 是 Java 并发包中高性能的线程安全哈希表实现,其线程安全设计经历了从 JDK 7 的分段锁到 JDK 8 的 CAS + synchronized 的演进。以下是其核心线程安全实现原理的全面剖析:
一、JDK 8 之前的实现(分段锁机制)
1. 分段锁(Segment)设计
final Segment<K,V>[] segments; // 分段数组
static final class Segment<K,V> extends ReentrantLock {
transient volatile HashEntry<K,V>[] table; // 段内哈希表
transient int count; // 段内元素计数
}
工作机制:
- 将整个哈希表分成多个 Segment(默认16个)
- 每个 Segment 独立加锁(继承 ReentrantLock)
- 不同 Segment 可并发操作
- 同一 Segment 操作需要获取锁
优点:锁粒度减小,并发度提升(最大并发数=Segment数)
二、JDK 8 及之后的实现(CAS + synchronized 优化)
1. 核心数据结构
transient volatile Node<K,V>[] table; // 主哈希表
private transient volatile int sizeCtl; // 控制标识符
private transient volatile CounterCell[] counterCells; // 并发计数
2. 关键线程安全技术
(1)CAS(Compare-And-Swap)操作
// 典型CAS操作示例(简化版)
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
Node<K,V> c, Node<K,V> v) {
return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}
- 用于无锁化的状态变更(如:数组初始化、节点插入)
- 通过 Unsafe 类直接操作内存
(2)精细化 synchronized 同步
- 仅锁住单个哈希桶(链表头节点/树根节点)
- 锁粒度从分段缩小到单个桶
synchronized (f) {
// f是链表头节点
// 处理链表/树的操作
}
(3)并发控制变量 sizeCtl
private transient volatile int sizeCtl;
- 负数:表示表正在初始化或扩容
- 0:默认初始值
- 正数:下一次扩容的阈值