一、使用背景

在阿里巴巴开发手册中,有这样一条规定:不要在foreach循环里进行add和remove操作(这里指的是List的add和remove操作),否则会抛出ConcurrentModificationException。remove元素请使用iterator。

f29f0bec6c933e9d6fb3fb414219ef4.png

二、源码

1.我们知道foreach是语法糖,他本质还是iterator进行的循环,因此下面的代码和使用foreach循环是一样的。在循环里面我们使用“错误”操作,使用List的add方法进行操作,会抛出ConcurrentModificationException

       ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("apple");
        Iterator<String> iterator = arrayList.iterator();
        while(iterator.hasNext()){
            String value = iterator.next();
            if("apple".equals(value)){
                arrayList.add("orange");
            }
        }

三、源码解析

1.arrayList.iterator();

①返回Itr类,并将modcount的值赋值给一个变量expectedModCount,其中modcount表示List实际被增删的次数,expectedModCount表示该迭代器期望被增删的次数,当新建Itr类的时候会给他赋初始值,只有通过该迭代器进行值的增删才会修改该值

1f94f5447debd05c92a2ce77cf2bf53.png

0f9094193aa7672ddd5392485494233.png

2.iterator.next();

①在调用迭代器的next方法时,他会进行检查,比较modCount和expectedModCount的值,如果不相等,Concurrent

a06c77dae6f16bf2838a90466954f5c.png

05b5c8ca957494affd4157961ac3763.png

四、总结

1.modCount和expectedModeCount不一致才会抛出ConcurrentModificationException。当我们调用List的remove方法时,他只会修改modCount的值;当我们调用iterator的remove方法,他会将modCount的值赋值给expectedModeCount

2.modCount和expectedModeCount是属于fast-fail机制,用于多线程中,当进行遍历的时候,有其他线程修改值的时候就会进行检查

五、解决方法

1.使用普通for循环进行操作

2.在循环中使用iterator进行操作

3.使用stream流进行过滤

4.使用fast-saft安全的类,如ConCurrentLinkedQueue


原来是小袁呐
1 声望0 粉丝