发布于2026-07-05 阅读(0)
扫一扫,手机访问
ConcurrentModificationException 可不是多线程的专利——单线程遍历集合时,如果你手痒直接调用 list.remove() 改动了集合结构,它照样会跳出来。背后的核心机制是 fail-fast:每次结构修改(比如 add、remove)都会更新 modCount,而迭代器内部记录着自己的 expectedModCount,两者一旦对不上,二话不说就抛异常,防止数据错乱甚至数组越界。那么,怎么避开这个坑?下面几种解法各有适用场景,挑对的那款就好。
这是最基础也最稳妥的单线程解法。关键在于,Iterator.remove() 和集合自带的 remove() 完全是两码事——它会在内部同步更新状态,所以不会触发校验失败。
next() 调用之后、下一次 next() 之前调用,否则会抛 IllegalStateException。Iterator 对象,得手动写迭代器循环。it.remove() ✅;list.remove(item) ❌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 跑得更快。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8