ConcurrentModificationException由modCount与expectedModCount不一致触发,体现fail-fast机制;单线程遍历中直接调用集合remove()也会触发,安全删除应使用Iterator.remove()、removeIf()或批量移除。

怎么防止在遍历集合时由于并发修改触发的快速失败异常

ConcurrentModificationException 是怎么被触发的

Java 的 ArrayListHashMap 等非线程安全集合,内部维护一个 modCount 计数器。每次结构修改(如 add()remove())都会递增它;而迭代器在创建时会记录当时的 expectedModCount。遍历时只要发现两者不一致,就立刻抛出 ConcurrentModificationException —— 这是「快速失败」(fail-fast)机制,不是并发安全保证,只是检测到“可能出错”就报错。

注意:这个异常不一定发生在多线程场景下。单线程里边遍历边用集合自身方法删元素,一样会触发:

List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
for (String s : list) {
    if ("b".equals(s)) list.remove(s); // ⚠️ 这里直接调用 list.remove() 就会爆
}

单线程遍历时安全删除的三种写法

核心原则:别让迭代器和集合的修改操作混在一起。推荐以下方式:

多线程环境下该选哪个集合

如果真有多个线程同时读写,不能只靠规避异常,得换线程安全的实现:

为什么增强 for 循环无法捕获 ConcurrentModificationException

增强 for 循环底层就是用 Iterator,但它把 next() 和异常处理全包在字节码里,你没法在循环体里 catch 它 —— 异常会直接跳出循环并向上抛。想兜底?只能在外层 try/catch,但这掩盖了根本问题:说明你的遍历逻辑本身存在结构性风险。

真正要警惕的,不是“怎么 catch 这个异常”,而是“为什么会在遍历中途改集合”。哪怕用 CopyOnWriteArrayList 避开了异常,若业务上要求强实时一致性,它返回的旧快照反而可能引入更隐蔽的 bug。

本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。