Java中Iterator遍历期间直接调用集合add()会触发ConcurrentModificationException,因fail-fast机制校验modCount;安全方式包括使用ListIterator.add()或分两阶段处理。

Java 中 Iterator 本身不支持遍历过程中动态添加元素,一旦在调用 next() 或 hasNext() 的同时,由其他代码(包括本线程)直接调用集合的 add()、remove() 等结构性修改方法,就会触发 ConcurrentModificationException。这不是偶然错误,而是迭代器的 fail-fast 机制主动抛出的保护性异常。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
为什么 add() 会立即冲突
Iterator 创建时会记录集合当前的修改计数 modCount;每次调用 next() 前都会校验该值是否被改动。只要集合底层数组扩容、元素位移或新增节点(哪怕只是 list.add("x")),modCount 就递增,校验失败即抛异常——与是否多线程无关,单线程下也必然发生。
安全添加的两种可行路径
-
用
iterator.remove()配合后续添加:先调next(),再调remove()删除当前元素,之后再调用集合的add()插入新元素。注意:这仍是“删后加”,不是“边遍历边原位置插入”,且不能保证新元素被本轮迭代访问到。 -
改用 ListIterator 的
add()方法:仅适用于List类型。它允许在游标当前位置前插入元素,且不会破坏迭代器状态。例如:
ListIteratorlit = list.listIterator();
while (lit.hasNext()) {
String s = lit.next();
if ("B".equals(s)) lit.add("D"); // 安全插入,不影响后续遍历
}
更推荐的替代方案
-
分两阶段处理:第一阶段用迭代器收集待添加的元素(如存入临时
List),第二阶段统一调用list.addAll(tempList)。逻辑清晰,无异常风险。 -
用 Java 8+ Stream 替代:对只读或转换类操作,优先使用
list.stream().map(...).filter(...).collect(...)。它不依赖传统迭代器,天然规避结构修改冲突。 -
选用 CopyOnWriteArrayList:若场景确实需要高并发读 + 动态写(如监听器列表),它的迭代器基于快照,
add()不影响正在运行的遍历,但要注意写操作开销大、读取看到的是旧视图。
哪些做法看似能用实则危险
- 在
for-each循环里调list.add():本质仍是迭代器,必定抛异常。 - 用
synchronized包裹整个 while 循环:虽能压制异常,但让遍历串行化,失去并发意义,且易引发锁竞争。 - 认为
Vector或Collections.synchronizedList()能解决迭代期添加问题:它们只保证单个方法原子性,无法维护跨多次调用的迭代器一致性。

















