ConcurrentModificationException 的核心是 modCount 与 expectedModCount 的校验机制,用于保障遍历期间集合结构一致性;modCount 记录结构性修改次数,expectedModCount 是迭代器初始化时复制的快照值,单线程下违反“遍历时不可结构性修改”契约也会触发该异常。

ConcurrentModificationException 的核心在于集合内部的 modCount 和迭代器持有的 expectedModCount 两个变量之间的校验关系。这不是线程同步问题的直接体现,而是一种结构一致性保障机制。
modCount 是什么?
modCount(modification count)是集合类(如 ArrayList、HashMap、LinkedList 等)中一个被 transient 修饰的 int 类型字段,用于记录该集合在结构上被修改的次数。
所谓“结构修改”,指改变集合大小或破坏遍历逻辑的操作,例如:
- 调用
add()、remove()、clear() - 触发扩容(如 ArrayList 的 grow())
- HashMap 的
put()引发 rehash
注意:仅修改元素内容(如 list.set(0, "new") 或 map.put(key, newValue))不会增加 modCount。
expectedModCount 的作用
当通过 iterator() 获取迭代器时,迭代器(如 ArrayList$Itr)会在构造阶段将当前集合的 modCount 值复制为自己的 expectedModCount。
AI 舌诊面诊问诊医疗系统 + 诊疗商城系统源码是一套结合 AI 辅助诊断与商品转化的健康类程序,基于浩创云、ThinkPHP(PHP)开发,支持微信服务号与 H5 端,适合做中医舌诊面诊问答、健康建议推送以及配套诊疗商品的运营。
这个值在迭代器生命周期内不会自动更新,它代表的是“我开始遍历时,集合应有的修改次数”。后续每次调用 next()、remove()、previous() 等方法前,都会执行 checkForComodification():
- 若
modCount == expectedModCount→ 继续操作 - 若
modCount != expectedModCount→ 立即抛出 ConcurrentModificationException
为什么单线程也会触发?
Fast-Fail 不等于多线程专属。只要在同一个线程中,用迭代器遍历的同时,又用集合自身的方法增删元素,就会导致 modCount 变更而 expectedModCount 滞后:
for (String s : list) { list.remove(s); }Iterator it = list.iterator(); while(it.hasNext()) { list.add("x"); it.next(); }
此时异常不是因为并发,而是违反了“遍历期间不得结构性修改”的契约 —— 这正是 fail-fast 设计的初衷:快速暴露逻辑错误,而非容忍不确定行为。
哪些集合有这个机制?
java.util 包下绝大多数非线程安全集合都启用此机制,包括:
- ArrayList、LinkedList、HashSet、TreeSet
- HashMap、TreeMap、WeakHashMap
- AbstractList 及其子类(如 Vector 虽线程安全,但其迭代器仍含该检查)
而 java.util.concurrent 包中的集合(如 ConcurrentHashMap、CopyOnWriteArrayList)采用不同设计(如复制、分段锁、CAS),不依赖 modCount 校验,因此不会抛出此异常 —— 它们属于 fail-safe 实现。

















