Fail-Fast迭代器(如ArrayList)在多线程遍历时检测到modCount不一致即抛ConcurrentModificationException;Fail-Safe迭代器(如CopyOnWriteArrayList)基于不可变快照遍历,不抛异常但看不到迭代中新增或删除的元素。

Java 迭代器在多线程环境下的表现,核心要看它所属的集合类型以及底层采用的迭代机制——主要是 Fail-Fast 和 Fail-Safe 两种策略。不同策略直接决定:是否抛异常、能否看到新数据、是否线程安全。
看集合类型:ArrayList 的迭代器会快速失败
ArrayList 返回的 Iterator 默认启用 Fail-Fast 机制:
- 迭代器创建时记录集合的修改计数(modCount)
- 遍历中若其他线程或本线程调用 add/remove 等方法,modCount 变更 → 下次调用 next() 或 hasNext() 就抛
ConcurrentModificationException - 即使只用一个线程,在 for-each 循环里调用 list.remove() 也会触发该异常
看集合类型:CopyOnWriteArrayList 的迭代器是安全失败
它用的是 Fail-Safe 机制,本质是“快照遍历”:
- 调用 iterator() 时,立即复制当前数组的一个不可变副本,迭代器只读这个副本
- 其他线程后续增删元素,会生成新数组并更新引用,但不影响已有迭代器
- 因此遍历过程绝不会抛 ConcurrentModificationException,也不会看到新增/删除的元素
- 迭代器的
remove()方法被禁用,调用即抛UnsupportedOperationException
注意同步包装类的陷阱:Collections.synchronizedList
它只是给每个写操作加了 synchronized,但迭代本身不自动同步:
- 如果多个线程同时遍历 + 修改,仍可能出错
- 正确用法是:手动对整个迭代块加锁,例如
synchronized(list) { for (x : list) { ... } } - 否则和直接用 ArrayList 在并发下表现类似,只是异常出现概率略低
实际选型建议
判断依据不是“要不要线程安全”,而是读写比例和一致性要求:
- 读远多于写(如配置监听器列表、事件回调队列)→ 优先 CopyOnWriteArrayList,迭代零成本、无锁
- 读写频繁且需强一致性(如共享状态缓存)→ 考虑 ConcurrentHashMap + 手动同步,或分段锁结构
- 仅需简单并发保护、写操作不多 → Collections.synchronizedList 配合显式同步块也可接受
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











