只读迭代本身不会触发concurrentmodificationexception,关键在于iterator检测到集合结构被修改且自身未参与;单线程下仅遍历安全,多线程需copyonwritearraylist、synchronized或concurrenthashmap等机制保障。

只读迭代本身不会触发 ConcurrentModificationException,但“只读”只是你的意图,不是 JVM 的保障。异常真正发生的原因是:**Iterator 检测到集合结构被修改(如 add/remove/clear),而它自己没参与这次修改**。所以,安全的关键不在于“你没写”,而在于“别人也不能在你遍历时乱写”。
明确区分单线程 vs 多线程场景
这是所有方案的前提:
-
单线程下:只要你不手动调用集合的
remove()或add(),只用iterator.next()和hasNext(),就不会抛异常——Iterator 不会因为你“只读”就主动检查,而是等你动了集合才拦。 -
多线程下:“只读迭代”依然可能崩溃:另一个线程在你调用
next()的间隙执行了list.add(),modCount 变了,当前 Iterator 就会在下次next()或hasNext()时抛异常。
多线程只读迭代的三种可靠方案
目标是让迭代过程对其他线程的修改“免疫”或“无感”:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
用 CopyOnWriteArrayList:每次
iterator()都返回一个当前数组的不可变快照,后续任何写操作都不影响正在遍历的迭代器。适合监听器列表、配置缓存等读远多于写的场景;写操作开销大,别用于高频更新。 -
用 synchronized 统一保护:所有对集合的访问(包括
iterator()、next()、add())都用同一把锁(推荐锁集合对象本身)。简单直接,但持有锁期间其他线程会被阻塞,吞吐受限。 -
改用 ConcurrentHashMap 的弱一致性迭代器:比如
map.keySet().iterator()。它不检查 modCount,不抛ConcurrentModificationException,允许并发修改;可能跳过刚插入的元素或重复看到已删除的,但绝不会崩溃。适合监控统计、批量通知等容忍短暂不一致的场景。
别踩这些常见误区
看似只读,实则埋雷:
- 增强 for 循环(
for (T t : list))底层仍是 Iterator,如果循环体里调用了list.remove(),照样抛异常——这不是“只读”,是伪装的修改。 - 以为加了
final List<t> list</t>就线程安全:final 只保证引用不变,不阻止集合内容被修改。 - 在迭代中调用业务方法,而该方法内部又偷偷修改了同一个集合:这属于逻辑耦合问题,需代码审查或设计隔离(如先收集待处理元素,再统一操作)。
真正的安全不是靠“不写”,而是靠机制兜底:快照、锁、或弱一致性。选哪个,取决于你对一致性、性能和场景的权衡。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










