ConcurrentModificationException本质是modCount与expectedModCount不一致触发的fail-fast机制,并非bug;泛型仅保障编译期类型安全,不解决迭代并发问题。

Java 中集合迭代失效(ConcurrentModificationException)本质是 modCount 与 expectedModCount 不一致 引发的 fail-fast 保护,不是 bug,而是设计约束。泛型本身不解决迭代安全问题,但它能从编译期杜绝类型误用,配合正确的迭代器使用方式,才能真正实现“安全处理数据”。关键不在泛型,而在如何用对迭代器、选对集合、避开共享状态。
泛型的作用:守住类型入口,但不干预并发逻辑
泛型确保你在编译时就只能往 List<string></string> 里加 String,避免运行时 ClassCastException;它也让 Iterator<string></string> 的 next() 直接返回 String,无需强制转换。但这和多线程修改、迭代器复用、结构变更等完全无关——泛型管类型,不管并发。
- 错误写法:
List list = new ArrayList(); list.add("a"); list.add(123); Iterator it = list.iterator(); String s = (String) it.next();→ 运行时报错 - 正确写法:
List<string> list = new ArrayList(); list.add("a"); // 编译期阻止 list.add(123); Iterator<string> it = list.iterator(); String s = it.next(); // 类型安全,无强转</string></string>
迭代器安全使用的三个硬性前提
无论是否带泛型,只要违反以下任一条件,就可能触发迭代失效:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 不要在遍历中直接调用集合的
add()或remove()方法(for-each循环中删元素必抛异常) - 不要把同一个
Iterator实例传给多个线程共用(每个线程必须调用自己的list.iterator()) - 不要在迭代过程中,由其他线程修改原集合结构(除非你用的是 Fail-Safe 集合)
结合泛型的推荐实践组合
泛型 + 正确迭代器用法 + 合适集合类型 = 真正的安全闭环:
立即学习“Java免费学习笔记(深入)”;
-
单线程只读遍历:用
List<string> list = new ArrayList();</string>+for (String s : list)或list.iterator()→ 简洁安全 -
单线程边遍历边删除:必须用
iterator.remove(),且仅限当前线程内操作Iterator<string> it = list.iterator(); while (it.hasNext()) { if (it.next().length() == 1) it.remove(); }</string> -
多线程只读遍历:优先选
CopyOnWriteArrayList<string></string>,它的iterator()返回基于快照的迭代器,天然支持并发读,不抛异常 -
多线程读写混合:改用
ConcurrentHashMap<string integer></string>,避免用keySet()或values()创建的迭代器做长周期遍历;如需遍历,建议先new ArrayList(map.keySet())快照再处理
哪些“看似泛型+迭代器”仍会出问题
这些情况泛型毫无保护作用,反而容易让人误以为安全:
-
synchronized(list) { for (String s : list) { ... } }→ 锁住集合方法,但无法锁住整个迭代过程,其他线程仍可能在锁外修改 -
List<string> syncList = Collections.synchronizedList(new ArrayList()); Iterator<string> it = syncList.iterator(); while (it.hasNext()) { ... }</string></string>→ 同步包装只保单个方法原子性,迭代器本身仍是 fail-fast,照样抛异常 for (int i = 0; i → 绕过迭代器,但若其他线程删了元素,<code>i可能越界或跳过元素,逻辑错乱

















