并发修改集合的迭代器陷阱:分析 ConcurrentModificationException 的变量快照解决

大瑶酱_2366

大瑶酱_2366

2026-05-07

384人浏览

原创

concurrentmodificationexception的根本原因是迭代器的modcount快照机制失效,该机制在单线程下校验修改一致性,多线程中因无锁和内存屏障而无法区分修改来源。

并发修改集合的迭代器陷阱:分析 concurrentmodificationexception 的变量快照解决

在多线程环境下遍历集合时抛出 ConcurrentModificationException,根本原因不是“并发修改”本身,而是迭代器内部维护的 modCount(修改计数)快照机制失效。它本质是一个单线程安全检测机制,被误用于多线程场景后暴露了设计局限。

modCount 快照机制如何工作

ArrayList、HashMap 等非线程安全集合在结构变更(add/remove/resize)时会递增自身 modCount 字段;而每个迭代器(如 ArrayList.Itr)在创建时会复制该值为 expectedModCount。每次调用 next() 或 remove() 前,都会检查二者是否一致:

  • 一致 → 继续迭代
  • 不一致 → 抛出 ConcurrentModificationException

这个检查发生在单次迭代操作入口处,不涉及锁或内存屏障,纯粹是“事后校验”。它无法区分:是其他线程改了集合?还是本线程在迭代中途自己调用了 list.remove()?——都算“非法修改”。

为什么“变量快照”不能解决并发问题

有人尝试用局部变量保存集合引用再遍历,例如:

List<string> snapshot = new ArrayList(originalList);
for (String s : snapshot) { ... }</string>

这确实避免了 CME,但不是因为解决了并发,而是绕开了检测机制**:你遍历的是副本,原集合怎么改都不影响副本的 modCount。**但它带来新问题:

  • 数据陈旧:副本生成后,原集合的新增/删除对本次遍历完全不可见
  • 内存开销:大集合频繁拷贝浪费资源
  • 逻辑错位:若遍历中需根据实时状态做决策(如跳过刚被标记删除的项),副本无法支撑

真正可靠的应对方式

应按场景选择语义正确的方案,而非依赖快照“蒙混过关”:

  • 读多写少 + 接受短暂不一致:用 Collections.unmodifiableList() 包装,或直接使用 CopyOnWriteArrayList(写操作复制数组,读操作无锁且永远不抛 CME)
  • 需要强一致性读写:改用线程安全集合(如 ConcurrentHashMap),注意其迭代器弱一致性——不抛 CME,但可能反映某次修改前/后的状态,不保证实时全量可见
  • 必须精确控制临界区:对原集合加显式锁(如 synchronized(list)),并在同步块内完成全部遍历与修改操作——此时 modCount 校验仍有效,且线程安全由锁保障

调试时的关键识别点

看到 CME 不要条件反射加锁或切集合类型。先确认:异常是否发生在多线程环境?还是单线程中迭代时调用了集合自身的 remove()?

  • 单线程:典型错误是 for-each 中调 list.remove(),应改用 Iterator.remove()
  • 多线程:说明有未协调的并发访问,需按上一条选型,而非简单加个局部变量

堆栈里出现 java.util.ArrayList$Itr.checkForComodification 就是 modCount 校验失败的铁证,它只告诉你“检测到了不一致”,不告诉你谁改的、何时改的——日志或调试器跟踪实际修改点才是关键。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

11057

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

8182

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

7072

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1184

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

968

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1436

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

2909

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20191

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1275

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.9万人学习