modCount是ArrayList、HashMap等集合类中记录结构性修改次数的int型非volatile字段,用于fail-fast机制:迭代器创建时复制该值,每次操作前比对,不一致则抛ConcurrentModificationException。

Java 中的 modCount 字段是 ArrayList、HashMap 等集合类内部用于支持 fail-fast 机制的核心计数器。它本身不直接“检测”修改,而是通过**版本比对**的方式,在迭代过程中发现结构性修改(如 add/remove)并快速抛出 ConcurrentModificationException。
modCount 是什么?
modCount(modification count)是一个 int 类型的非 volatile 字段,记录集合自创建以来发生过的结构性修改次数。所谓“结构性修改”,是指改变集合大小或内部结构的操作,例如:
-
add()/remove()(包括clear()) -
put()/remove()在HashMap中触发扩容或节点调整 - 但不包括
set()(如ArrayList.set())这类仅替换元素、不改变 size 或结构的操作
迭代器如何利用 modCount 实现 fail-fast?
每个集合的迭代器(如 ArrayList.Itr)在创建时会把当前集合的 modCount 值复制到自己的 expectedModCount 字段中。之后每次调用 next() 或 remove() 时,都会检查两者是否一致:
- 如果
modCount != expectedModCount,说明集合被外部线程或同一线程的其他代码修改过 → 立即抛出ConcurrentModificationException - 迭代器自身的
remove()方法会同步更新expectedModCount,避免误报
这种设计不是为了解决并发安全问题(它不提供同步),而是为了**及早暴露错误使用方式**——比如边遍历边用集合方法增删元素。
立即学习“Java免费学习笔记(深入)”;
为什么 fail-fast 不是线程安全保证?
modCount 没有 volatile 修饰,也不加锁,因此它在多线程下无法保证可见性或原子性。fail-fast 只能在**单线程误操作**或**弱并发场景下偶然触发**时起作用:
- 两个线程同时修改集合 + 同时迭代 → 可能不抛异常(因为 race condition 导致比对恰好一致),也可能抛异常,结果不确定
- 真正需要线程安全,请用
CopyOnWriteArrayList、ConcurrentHashMap或显式加锁
常见触发 fail-fast 的典型写法
以下代码会在运行时抛出 ConcurrentModificationException:
ArrayList<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
for (String s : list) {
if ("b".equals(s)) {
list.remove(s); // ❌ 在增强 for 循环中直接 remove
}
}
正确做法是使用迭代器的 remove():
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if ("b".equals(s)) {
it.remove(); // ✅ 安全删除
}
}


















