示例代码

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的代码)。

多线程

  1. 在使用iterator迭代的时候使用synchronized或者Lock进行同步;
  2. 使用并发容器CopyOnWriteArrayList代替ArrayList和Vector。