modcount是arraylist的结构性修改计数器,add、remove、clear会使其自增,而set、get等非结构性操作不改变它;itr通过比对modcount与expectedmodcount实现fail-fast机制。

ArrayList 的迭代器(Itr)通过modCount 和 expectedModCount 的比对实现快速失败(fail-fast),本质是检测迭代过程中是否发生了非迭代器自身的结构性修改。
modCount 是什么
它是 ArrayList 维护的一个修改计数器,每次调用 add、remove、clear 等改变集合结构的方法时,modCount 自增。它不记录元素内容变化(如 set),只响应容量或节点数量的变动。
-
add(E)→ modCount++ -
remove(int)→ modCount++ -
set(int, E)→ modCount 不变 -
trimToSize()→ modCount 不变(未改变逻辑结构)
Itr 如何触发快速失败
迭代器在构造时将当前 modCount 值赋给自己的 expectedModCount;此后每次调用 next() 或 remove() 前,都会检查二者是否相等。一旦不等,立刻抛出 ConcurrentModificationException。
- 这是检测而非预防:异常发生在操作执行后、下一次迭代检查时
- 即使单线程,只要在迭代中用
list.remove()而非itr.remove(),也会触发 - 子类如
SubList有自己的modCount视图,规则同样适用
为什么 set 不影响快速失败
set(int, E) 只替换指定位置的引用,不改变数组长度、不移动元素、不触发扩容或缩容,因此不变更 modCount。迭代器无法感知这种“非结构性”修改,也不会失败——这属于设计取舍,不是 bug。
- 类似地,
get(int)、contains(Object)等只读操作也不影响计数 - 若需严格一致性(包括内容变更也需同步感知),应使用
CopyOnWriteArrayList
如何安全地边遍历边删除
唯一被允许的结构性修改方式是调用迭代器自身的 remove() 方法,它会在删除元素后同步更新 expectedModCount,保持与 modCount 一致。
- 错误写法:
for (String s : list) { if (s.isEmpty()) list.remove(s); } - 正确写法:
for (Iterator<string> it = list.iterator(); it.hasNext();) { String s = it.next(); if (s.isEmpty()) it.remove(); }</string> - Java 8+ 也可用
removeIf(Predicate),它内部封装了安全的迭代逻辑









