集合迭代时修改元素
示例代码
public class ListAddMain {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
for (String s : list) {
System.out.println(s);
if("1".equals(s)) {
list.remove(s);
}
}
}
}
// ---------- 输出 -----------------
/*
1
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:911)
at java.util.ArrayList$Itr.next(ArrayList.java:861)
at pers.jy.demo.modules.test.yst.ListAddMain.main(ListAddMain.java:20)
*/
原因
modCount 用来记录 ArrayList 结构发生变化的次数。结构发生变化是指添加或者删除至少一个元素的所有操作,或者是调整内部数组的大小,仅仅只是设置元素的值不算结构发生变化。在进行序列化或者迭代等操作时,需要比较操作前后 modCount 是否改变,如果改变了会抛出 ConcurrentModificationException。
关键点就在于:调用list.remove()方法导致modCount和expectedModCount的值不一致。
注意,像使用for-each进行迭代实际上也会出现这种问题。
解决方案
单线程
使用list.iterator()来进行迭代,调用itr.remove()方法(itr.remove()方法有修改modCount的代码)。
多线程
- 在使用iterator迭代的时候使用synchronized或者Lock进行同步;
- 使用并发容器CopyOnWriteArrayList代替ArrayList和Vector。