ConcurrentHashMap 通过分段无锁化实现高效线程安全:Java 8+ 采用 CAS 操作处理无竞争场景,synchronized 锁单个桶头节点,读操作依赖 volatile 字段全程无锁,扩容支持多线程协作,且提供 putIfAbsent 等原子复合方法。

ConcurrentHashMap 实现高效线程安全,核心在于“不锁全表、少锁数据、读不加锁、写锁到点”。它不是靠一把大锁硬扛并发,而是用分层策略把竞争拆开、把操作原子化、把可见性保障到位。
细粒度锁 + CAS 无锁协作
Java 8+ 彻底弃用 Segment 分段锁,改用更轻量的组合机制:
- CAS 操作用于无竞争场景:比如插入新节点到空桶、更新 sizeCtl(扩容控制变量)、初始化数组——这些操作通过 Unsafe.compareAndSwapObject 等原子指令完成,完全无锁,开销极小。
- synchronized 锁住单个桶头节点:当多个线程争抢同一个桶(比如链表头或红黑树根)时,只锁定该 Node 对象。其他桶不受影响,不同桶的 put/remove 可完全并行。
- 锁范围最小化:不是锁整个链表或整棵树,而是锁住链表第一个节点(Node)或树根封装节点(TreeBin),后续遍历和修改都在同步块内完成,避免锁扩散。
读操作全程无锁,靠 volatile 保证可见性
get 方法从不加锁,性能接近 HashMap,依赖两个关键设计:
- Node 的 val 和 next 字段都是 volatile:确保写线程对值或链表结构的修改,能立即被读线程看到。
- table 数组引用也是 volatile:扩容时 new table 赋值给 table 字段的操作具有可见性,读线程可能读到新旧两版数组,但不会读到中间态或损坏结构。
- 即使在扩容中,get 也能安全访问——遇到 ForwardingNode(转发节点)会自动跳转到新表查询,用户无感。
扩容支持多线程协助,不阻塞读写
扩容不再是单线程串行任务,而是可协作的并发过程:
立即学习“Java免费学习笔记(深入)”;
- 触发扩容时,sizeCtl 设为负数(如 -2 表示有 1 个线程在扩容),其他线程检测到后可主动加入迁移工作。
- 每个线程负责迁移 table 中一段连续的桶(例如从 i 到 i+stride),迁移完标记为 ForwardingNode,避免重复处理。
- 读写操作与迁移并行:get 可查新旧表;put 若命中 ForwardingNode,会先帮着迁移再插入,提升整体进度。
原子复合操作减少手动同步需求
提供一系列“检查+执行”一体的原子方法,避免外部 if-else + put 这类非原子组合:
- putIfAbsent:键不存在才插入,底层用 CAS 或 synchronized 保证一次完成。
- computeIfAbsent:键不存在时调用函数生成值并存入,且函数最多执行一次(即使多线程同时触发)。
- merge / replace:基于旧值计算新值并更新,整个过程不可分割。
- 这些方法内部已封装好锁或 CAS 逻辑,开发者无需额外同步,既安全又简洁。


















