You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java集合并发修改检测机制解析:ConcurrentModificationException原理

为什么遍历集合时删除元素会触发ConcurrentModificationException?

我们都知道,在遍历Java集合时直接删除元素会抛出ConcurrentModificationException,比如这段错误代码:

for(Map.Entry<String, String> entry : testMap.entrySet()) {
  if(entry.getValue().equalsIgnoreCase("Sample")) {
    testMap.remove(entry.getKey());
  }
}

核心原理:modCount与expectedModCount的校验

Java并没有什么特殊标记来"监控"这个循环,它靠的是集合内部的修改计数机制:

  • 所有非并发安全的集合(比如HashMap、ArrayList)内部都有一个modCount变量,用来记录集合被修改(添加、删除元素)的次数。
  • 增强for循环只是Java的语法糖,编译后会被转换成迭代器(Iterator)遍历的代码——也就是说,你写的这段循环底层其实是在使用集合的迭代器。
  • 迭代器初始化时,会把当前集合的modCount值复制到自己的expectedModCount变量里。
  • 每次调用迭代器的next()方法获取下一个元素前,都会检查modCount和expectedModCount是否相等:如果不等,说明集合在迭代过程中被外部修改了(比如直接调用集合的remove()方法),就会抛出ConcurrentModificationException。

为什么直接调用集合remove会触发异常?

上面的错误代码里,遍历依赖迭代器,但删除操作直接调用了testMap.remove()——这个操作会修改集合的modCount,但迭代器的expectedModCount并没有同步更新。当下一次迭代器执行next()时,发现两个计数不一致,就会触发异常。

正确的做法

如果要在遍历过程中删除元素,应该用迭代器自己的remove()方法:

Iterator<Map.Entry<String, String>> iterator = testMap.entrySet().iterator();
while (iterator.hasNext()) {
    Map.Entry<String, String> entry = iterator.next();
    if(entry.getValue().equalsIgnoreCase("Sample")) {
        iterator.remove(); // 这个方法会同步更新modCount和expectedModCount
    }
}

迭代器的remove()方法在删除元素后,会把自己的expectedModCount更新为最新的modCount,这样就不会触发异常了。

内容的提问来源于stack exchange,提问作者Elimination

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 15:15:13