ConcurrentHashMap采用安全失败机制,其迭代器基于创建时的快照遍历,不抛ConcurrentModificationException,也不反映遍历中发生的增删操作,无modCount校验,通过分段锁(JDK1.7)或CAS+synchronized(JDK1.8)实现弱一致性读取。

ConcurrentHashMap 采用安全失败(fail-safe)机制,是因为它的迭代器不直接操作原始数据结构,而是基于某一时刻的“快照”进行遍历。
迭代器读取的是内部状态的快照
ConcurrentHashMap 的 entrySet()、keySet()、values() 等返回的迭代器,并不持有对底层哈希表的实时引用。它在创建时会尝试获取当前分段或桶数组的一致视图(JDK 1.7 是 Segment 数组的可见状态;JDK 1.8 是 Node[] 数组的 volatile 引用),后续遍历都基于这个已确定的状态进行。
这意味着:即使其他线程正在并发修改 map(put/remove),迭代器看到的数据仍是它开始遍历时已存在的元素——不会抛 ConcurrentModificationException,也不会反映新增或刚删除的项,但也不会出错或崩溃。
底层无 modCount 校验逻辑
与 HashMap、ArrayList 不同,ConcurrentHashMap 的迭代器类(如 KeyIterator、EntryIterator)中没有 expectedModCount 字段,也不检查 modCount 是否变化。
- HashMap 迭代器每次 next() 前都会调用 checkForComodification(),比对 modCount 和 expectedModCount
- ConcurrentHashMap 完全绕开了这套校验机制,因为它设计目标就是支持高并发下的“弱一致性”读取
写操作不影响已有迭代过程
ConcurrentHashMap 的并发控制是精细化的:
- JDK 1.7 使用 Segment 分段锁,不同段之间互不影响;读操作甚至完全无锁,靠 volatile 保证可见性
- JDK 1.8 使用 CAS + synchronized 锁单个桶(链表头或红黑树根),写操作只影响局部节点
- 迭代器遍历时若遇到正在扩容的桶,会主动读取新表对应位置;若遇到被移除节点,则跳过——整个过程不依赖全局结构稳定性
这是有意为之的弱一致性保证
安全失败不是“忽略问题”,而是明确接受一种可预期的行为:遍历结果可能不包含最近写入的内容,也可能包含已被逻辑删除但尚未清理的残留节点(取决于具体实现和时机),但它稳定、不中断、不抛异常。
这种设计让 ConcurrentHashMap 在高并发读多写少场景下,既避免了锁竞争,又提供了可用的遍历能力,比加锁遍历或复制整个 map 更高效。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











