ConcurrentHashMap迭代器采用弱一致性,不保证看到全部最新修改,而是通过volatile字段、分段锁或桶级锁、ForwardingNode等机制实现安全遍历,不阻塞写入且不支持remove操作。

ConcurrentHashMap 的迭代器不追求“看到全部最新修改”,而是通过底层结构设计,在不加锁、不复制数据的前提下,保证遍历过程安全、不崩溃、不阻塞写入——这就是弱一致性(weakly consistent)的实质。
基于分段锁或桶级锁的非阻塞读取
在 JDK 7 中,ConcurrentHashMap 使用 Segment 分段锁;JDK 8 起改用 CAS + synchronized 锁单个桶头节点。迭代器遍历时,每个桶(bin)是独立处理的:
- 读取某个桶时,只依赖 volatile 的 table 引用和节点的 volatile next 字段,无需加锁
- 若当前桶为空或正在被扩容,迭代器直接跳过,不会等待或重试
- 遍历到某节点时,即使该节点正被其他线程删除(如 next 指向自身),迭代器也能识别并跳过,避免死循环
不冻结快照,也不校验修改计数
它不像 HashMap 那样维护 modCount 并在 next() 时比对——ConcurrentHashMap 根本不记录全局修改次数:
- 迭代器创建后,不锁定任何数据结构,也不生成副本
- 遍历时看到的是“某一时刻各桶状态的拼接视图”,不同桶可能反映不同时间点的数据
- 因此,新插入的元素可能被跳过(尤其插在已遍历过的桶里),刚删除的节点也可能仍被访问到(逻辑删除未完成物理清理)
利用 volatile 和 happens-before 保障基础可见性
弱一致性不是“完全不可靠”,它依赖 Java 内存模型的关键约束:
立即学习“Java免费学习笔记(深入)”;
- HashEntry 的 value、next 字段声明为 volatile,确保写入后对迭代器可见(有 happens-before 关系)
- Segment 的 count 字段(JDK 7)或 Node 数组的 volatile 引用(JDK 8+)让迭代器能感知桶是否已初始化或正在转移
- 扩容时,ForwardingNode 会标记迁移中桶,迭代器遇到就转向新表继续,保证不漏、不重复
迭代器本身不支持修改操作
为简化并发逻辑,ConcurrentHashMap 的 keySet().iterator()、values().iterator() 等均不支持 remove():
- 调用 iterator.remove() 直接抛 UnsupportedOperationException
- 所有写操作必须通过 map.put()/compute()/remove() 等方法进行,由底层 CAS 或锁机制统一协调
- 这种“只读迭代器”设计,避免了在遍历路径上引入额外同步开销


















