ConcurrentHashMap 通过无锁读、桶级写锁、CAS更新和并发扩容实现高效线程安全:读操作全无锁,写仅锁单个桶头节点,复合操作由原子方法保障,扩容支持多线程分段协作。

ConcurrentHashMap 实现高效线程安全,并不是靠“一把大锁”,而是通过细粒度控制 + 无锁读 + 原子操作协同完成的。核心在于:读不加锁、写只锁局部、更新靠 CAS、扩容可并发。
读操作完全无锁
get、containsKey、isEmpty 等读方法不使用任何锁,直接通过 volatile 修饰的数组和节点字段读取数据。JVM 内存模型配合 volatile 的 happens-before 规则,保证其他线程写入后能被及时看到。这意味着成百上千个线程同时读,零竞争、零阻塞。
写操作只锁单个桶(Node)
Java 8+ 版本已废弃 Segment 分段锁,改用更轻量的机制:
- 定位到哈希桶(table[i])后,若该桶为空,直接 CAS 插入新节点
- 若桶头节点存在,先用 synchronized 锁住该桶的首节点(而非整个 map)
- 在临界区内完成链表插入或红黑树转换等逻辑,锁粒度最小化
复合操作提供原子性保障
避免“读-改-写”竞态的经典陷阱,ConcurrentHashMap 提供了多个函数式原子方法:
立即学习“Java免费学习笔记(深入)”;
- putIfAbsent(key, value):键不存在才插入
- remove(key, value):值匹配才删除
- replace(key, oldValue, newValue):旧值匹配才替换
- computeIfAbsent(key, mappingFunction):线程安全地懒加载缓存
- merge(key, value, remappingFunction):存在则合并,否则设值
这些方法内部由 CAS 或桶级锁+重试机制保障整体执行的原子性,无需手动同步。
扩容支持多线程协作
当 table 需要扩容时,ConcurrentHashMap 不会阻塞所有写操作:
- 扩容以“分段迁移”方式进行,多个线程可并行协助迁移不同桶的数据
- 迁移中,新旧 table 可同时服务请求:未迁移桶走旧表,已迁移桶走新表
- 通过特殊 ForwardingNode 标记迁移状态,读写操作自动感知并配合
这种渐进式扩容极大降低了长尾延迟,避免了传统全局 rehash 的停顿问题。


















