java并发容器天然不触发concurrentmodificationexception,因其采用无锁、快照、分段或弱一致性策略替代fail-fast机制;如copyonwritearraylist通过数组复制实现读写分离,concurrenthashmap提供弱一致性迭代,concurrentlinkedqueue等则依赖cas保证线程安全。

Java 并发容器不是“避免抛异常”,而是从设计上让迭代与修改能安全共存,从而**天然不触发** ConcurrentModificationException。关键在于它们不依赖传统的 fail-fast 机制,而是采用无锁、快照、分段或弱一致性等策略。
CopyOnWriteArrayList:读操作零阻塞,写操作基于快照
它适用于读远多于写的场景(如事件监听器列表、配置项缓存):
- 每次 add/remove 都复制整个底层数组,新迭代器看到的是创建时刻的快照,因此遍历时增删不会影响当前迭代
- 迭代过程完全无锁,for-each 安全可用:
for (String s : list) { if (s.contains("log")) list.remove(s); } - 缺点明显:写操作内存开销大、GC 压力高,不适合高频更新或大数据量
ConcurrentHashMap:迭代不阻塞写,但注意方法语义
它不提供强一致性迭代,但保证不会因并发修改而抛 CME:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
keySet()、values()、entrySet()返回的集合支持安全遍历,即使其他线程正在 put/remove - 迭代结果反映的是某个时间点的近似状态(弱一致性),不会漏项也不会重复,但不保证实时精确
- 慎用
computeIfAbsent等复合操作在遍历中——需查阅 Javadoc,部分方法在迭代期间调用可能引发死锁或未定义行为
ConcurrentLinkedQueue / ConcurrentSkipListMap:无锁+弱一致性保障
这些容器底层使用 CAS 和非阻塞算法,迭代器不校验 modCount:
-
ConcurrentLinkedQueue的 iterator 是弱一致性的:可遍历到已入队但尚未出队的元素,也可能跳过刚入队的元素,但绝不会抛 CME -
ConcurrentSkipListMap支持有序遍历,其 keySet.values() 迭代也无需外部同步,适合需要排序且高并发的场景 - 所有操作都不依赖全局锁,吞吐量高,但内存占用略高
不推荐的“伪线程安全”方案
像 Collections.synchronizedList(new ArrayList()) 这类包装类,只是给每个方法加了 synchronized,不能解决迭代时修改的问题:
- 增强 for 循环仍会通过 iterator 遍历,而 iterator 本身未被同步保护,CME 照样发生
- 正确用法必须显式同步整个迭代块:
synchronized(list) { for (E e : list) { ... } } - 这种粗粒度锁严重限制并发度,性能差,应优先选用真正为并发设计的容器
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










