Java 中如何处理集合的并发修改异常
作者:小确幸
时间:2026-07-05
浏览:0
单线程遍历集合时直接调用移除方法会因修改计数与预期计数不一致引发并发修改异常。解决方案包括使用迭代器的移除方法安全删除、Java8的按条件移除批量过滤、多线程场景选用写时复制数组等并发集合,或暂存待删列表后统一删除。
ConcurrentModificationException 可不是多线程的专利——单线程遍历集合时,如果你手痒直接调用 list.remove() 改动了集合结构,它照样会跳出来。背后的核心机制是 fail-fast:每次结构修改(比如 add、remove)都会更新 modCount,而迭代器内部记录着自己的 expectedModCount,两者一旦对不上,二话不说就抛异常,防止数据错乱甚至数组越界。那么,怎么避开这个坑?下面几种解法各有适用场景,挑对的那款就好。
用 Iterator.remove() 安全删除
这是最基础也最稳妥的单线程解法。关键在于,Iterator.remove() 和集合自带的 remove() 完全是两码事——它会在内部同步更新状态,所以不会触发校验失败。
- 必须紧跟在
next()调用之后、下一次next()之前调用,否则会抛IllegalStateException。 - 增强 for 循环里用不了,因为拿不到
Iterator对象,得手动写迭代器循环。 - 写法示例:
it.remove()✅;list.remove(item)❌
优先用 removeIf() 批量过滤
Ja va 8 之后,官方推荐用 removeIf(),一句话搞定,底层走的也是安全的迭代逻辑,比手写 Iterator 更简洁、更不容易出错。
- 适用于
List、Set等实现了该方法的集合。 - 写法:
list.removeIf(x -> x.startsWith("A")),语义清晰,一行解决。 - 比起“先收集再删”,它更省内存,也不用担心索引偏移的问题。
多线程场景选对并发集合
别一根筋用 synchronized 硬锁,优先考虑专为并发设计的集合,效果和性能都好得多。
CopyOnWriteArrayList:适合读多写少的场景(比如监听器列表),遍历时可以安全增删,但每次写都会复制整个数组,写频繁时 GC 压力不小。ConcurrentHashMap:高并发 Map 操作的首选,它的keySet()、values()迭代不会抛 CME。注意像computeIfAbsent这样的方法要按文档使用。- 尽量避开
Collections.synchronizedList:它只是给每个方法加了锁,遍历时你仍得手动同步整个代码块,容易漏掉,而且性能一般。
复杂逻辑用暂存+统一删除
如果判断条件太复杂,用不了 removeIf,又不想换集合类型,那这个兜底方案就很实用。
- 新建一个临时集合(比如
ArrayList或HashSet),用来存放待删除的元素。 - 遍历原集合时只做判断和收集,千万别去动原集合的结构。
- 遍历结束后,统一调用
list.removeAll(toRemove),或者逐个remove()。 - 小技巧:如果原集合是
HashSet,用HashSet来存待删项,能让removeAll跑得更快。
作者最新文章
Photoshop抠图教程详细步骤图解:新手入门常用方法与技巧
2026-09-22 14:38
Windows 10
2026-09-16 17:44
Python安装后怎么打开:使用IDLE或命令行启动解释器
2026-09-16 13:54
Windows系统Python安装教程:下载、勾选PATH及环境变量配置
2026-09-16 13:53
“等灯不计时”落地解析:算法善意如何转化为技术能力与生态协同
2026-09-08 18:03
热门文章
更多
精品专题
更多
Mac软件
更多
WINDOWS
更多


































