关于java:ArrayList中foreach循环中增添删除导致ConcurrentModificationException

45次阅读

共计 1074 个字符,预计需要花费 3 分钟才能阅读完成。

一、应用背景

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

二、源码

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 类的时候会给他赋初始值,只有通过该迭代器进行值的增删才会批改该值

2.iterator.next();

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

四、总结

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

正文完
 0