Fail-Fast机制通过modCount与expectedModCount校验实现:迭代器创建时拷贝modCount为expectedModCount,每次next()/hasNext()前比对二者,不等则抛ConcurrentModificationException;Iterator.remove()安全因同步更新expectedModCount。

Java 中 Iterator 本身不保证数据强一致性,它通过 fail-fast 机制在单线程场景下提供“及时发现不一致”的能力,本质是检测而非保障。
fail-fast 是怎么工作的
ArrayList、HashMap 等非线程安全集合的迭代器依赖两个关键字段:
- modCount:集合内部维护的修改计数器,每次 add、remove、clear 等结构性修改都会自增;
- expectedModCount:迭代器创建时从集合拷贝的 modCount 值,后续每次调用 next() 或 hasNext() 前都会校验是否仍相等。
一旦外部代码绕过迭代器直接修改集合(比如 list.remove(obj)),modCount 变化而 expectedModCount 未同步,下一次迭代操作就会抛出 ConcurrentModificationException。
为什么 remove() 方法是安全的
Iterator.remove() 是唯一被允许的删除方式,因为它会主动同步两个计数器:
- 先执行集合的删除逻辑;
- 再将 expectedModCount 设为当前 modCount 值;
- 这样后续迭代仍可继续,不会中断。
注意:必须在调用 next() 之后才能调用 remove(),否则因 lastRet == -1 抛 IllegalStateException。
并发场景下它不适用
fail-fast 不是线程同步机制,仅用于开发期快速暴露错误。多线程同时读写时:
- 它可能漏检(因检查点有限);
- 也无法防止脏读或部分更新;
- 此时应改用线程安全容器,如 CopyOnWriteArrayList(迭代器基于快照,无 fail-fast)、ConcurrentHashMap(提供弱一致性迭代器,不抛异常但可能看不到最新写入)。
真正保障一致性的做法
若业务要求遍历期间数据完全不变,不能依赖迭代器自身机制,而需外部控制:
- 加锁:对整个遍历过程加 synchronized 或 ReentrantLock;
- 不可变快照:如 Collections.unmodifiableList(list) 或 List.copyOf(list),确保遍历时底层数组不被修改;
- 使用 CopyOnWriteArrayList:迭代器持有一份创建时刻的数组副本,遍历与写入完全隔离。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











