java迭代器fail-fast机制旨在提前暴露结构性修改错误,通过modcount与expectedmodcount比对,在非迭代器方式修改集合时抛concurrentmodificationexception;它非并发控制手段,仅用于快速定位写法问题。

Java 迭代器失效(Fail-Fast)机制不是“出错了才处理”,而是设计用来**提前暴露结构性修改错误**——只要迭代过程中集合被非迭代器方式修改,就大概率抛 ConcurrentModificationException。它不防并发,也不保数据一致,只帮你快速定位写法问题。
触发 Fail-Fast 的典型场景
核心条件:**迭代器正在遍历,集合结构被改变(add/remove/clear),且修改不是通过迭代器自身方法完成的。**
-
单线程中增强 for 循环里调用集合的 remove() 或 add():比如
for (String s : list) { if ("a".equals(s)) list.remove(s); }—— 立刻触发异常 - 多线程下,一个线程用 Iterator 遍历,另一个线程直接调用 list.add()/remove():即使遍历和修改错开时间,也极易因 modCount 可见性问题触发
-
Iterator 创建后、遍历前,集合被其他代码修改过:比如先
list.add(x),再iterator = list.iterator(),但此时expectedModCount已落后于当前modCount
根本解决思路:避开触发条件,而非捕获异常
依赖 try-catch ConcurrentModificationException 是反模式。正确做法是从源头消除结构性修改与迭代的冲突。
-
单线程遍历时要删除元素 → 用 Iterator.remove():它会同步更新
expectedModCount,例如while(it.hasNext()) { String s = it.next(); if (s.equals("x")) it.remove(); } -
需要边遍历边增删多个元素 → 收集待操作元素,遍历完再统一处理:比如先
List<string> toRemove = new ArrayList()</string>,循环中toRemove.add(s),结束后调用list.removeAll(toRemove) -
多线程读写混合场景 → 换线程安全集合:读多写少用
CopyOnWriteArrayList(迭代器基于快照,不触发 Fail-Fast);高并发读写用ConcurrentHashMap(其迭代器是弱一致性,不抛该异常) -
纯只读场景 → 用不可变集合:如
List.of("a", "b")或ImmutableList.copyOf(list),从 API 层禁掉所有修改入口,彻底杜绝失效可能
理解底层:modCount 和 expectedModCount 是关键
每个支持 Fail-Fast 的集合(如 ArrayList、HashMap)都维护一个 modCount 字段,记录结构性修改次数;迭代器创建时把当时值存为 expectedModCount。每次调用 next() 前,都会比对二者 —— 不等就立即失败。
注意:这个检查不是原子或同步的,所以不能当作并发控制手段。它只是调试辅助,不是运行时保障。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











