为什么在foreach循环中进行元素remove/add操作,会抛ConcurrentModificationException 异常?

运行以下代码:

 @Test
    public void test() {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        for (String temp : list) {
            // 当为A时运行正常,改成B时异常ConcurrentModificationException
            if ("B".equals(temp)) {
                list.remove(temp);
            }
        }
    }

运行结果:

编译后的Class文件:

 @Test
    public void test() {
        List<String> list = new ArrayList();
        list.add("A");
        list.add("B");
        Iterator var2 = list.iterator();

        while(var2.hasNext()) {
            String temp = (String)var2.next();
            if("B".equals(temp)) {
                list.remove(temp);
            }
        }

    }

可以发现源码与编译后的字节码不一样,源码中的“for (String temp : list) {”在真实的字节码中是

“Iterator var2 = list.iterator();
while(var2.hasNext()) {
    String temp = (String)var2.next();”

对应的源码:

list.iterator()对应方法的源码:

new Itr()创建对象时,会将modCount值赋值给expectedModCount,而modCount该字段在ArrayList中标识当前对象的修改次数(包括remove和add方法)

add()

remove()

进入while循环时,执行var2.hasNext()方法:

cursor初始化的时候是0,每执行一次next()方法,值自动加1,cursor == size时会跳出循环

当执行next()方法时,首先会执行checkForComodification()方法

查看代码,可以看出当modCount != expectedModCount时,就会抛出ConcurrentModificationException

expectedModCount的值是在创建Itr对象赋值的,而遍历集合的时候,再执行一次remove或add就会导致modCount的值修改,而此时expectedModCount的值未变化,就会报异常ConcurrentModificationException。

如果非要在循环里面remove、add 元素,请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁。

  ListIterator iterator = list.listIterator();
        while (iterator.hasNext()) {
            String item = (String) iterator.next();
            if("B".equals(item)){
                iterator.add("C");
//                iterator.remove();
            }
            System.out.println("改变后的数据:" + list.toString());
        }

猜你喜欢

转载自blog.csdn.net/weixin_37934748/article/details/84775005
今日推荐