迭代器边遍历边删除存在的问题

迭代器边遍历边删除存在的问题以及原理

01-问题

​ 我们先来看看如下代码

java 复制代码
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(5);
        list.add(4);
        list.add(3);
        list.add(2);
        list.add(7);
        list.add(0);
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

​ 我们运行查看结果,可以正常运行输出,如下图所示

​ 上述是可以正常遍历的,我们修改一下代码再来运行

java 复制代码
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(5);
        list.add(4);
        list.add(3);
        list.add(2);
        list.add(7);
        list.add(0);
        Iterator<Integer> iterator = list.iterator();
        while (iterator.hasNext()){
            Integer next = iterator.next();
            list.remove(next);
            System.out.println(next);
        }
    }

​ 上述代码我们点击运行,会抛出异常,如下所示

我们来看一下问题所在。

02-原因分析

​ 我们点进去ArrayList获取迭代器的方法,可以看到返回了一个ListItr对象

​ 我们继续点进去,查看ListItr的源码,看到继承了Itr类,我们继续进入

​ 我们进入Itr的源码进行分析

java 复制代码
    private class Itr implements Iterator<E> {
        // 下一个元素的下标索引
        int cursor;       // index of next element to return
        // 上一个元素的下标索引
        int lastRet = -1; // index of last element returned; -1 if no such
        // 记录版本号信息,modCount是List继承的Abstract的
        int expectedModCount = modCount;

        Itr() {}

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

​ 我们首先关注到有三个属性,先来解释一下

  • **cursor:**下一个要访问元素的下标索引
  • **lastRet:**上一个访问过元素的下标索引
  • expectedModCount:我们可以看到这个属性赋值为modCount,我们点进去查看,发现其在List继承的AbstractList类中,我们翻译一下,可以看到其解释,原来这个是用来记录List被修改的次数,默认是0

​ 在我们使用List的add()、remove()、等方法的时候,会对modCount进行++的操作,表示该集合被修改的次数,我们注意到在迭代器的next()中,使用了checkForComodification()方法,在该方法中,当modCount != expectedModCount时,会抛出异常,可以看到我们一开始抛出的异常就是这个,原来在我们调用remove方法的时候,修改了modCount ,但是expectedModCount没变,所以导致不一致了。

那为什么要有这个机制呢,这个机制其实是一个类似于乐观锁一样,为了防止并发的时候使用迭代器遍历的时候,List被别的线程修改,导致出现的问题

相关推荐
隔窗听雨眠4 分钟前
Nginx网关响应慢排查手记
java·服务器·nginx
智慧物业老杨29 分钟前
智慧物业合同周期管理系统:从风险预警到智能交接的全流程数智化落地方案
java·人工智能·python
源码宝1 小时前
MES系统源码:Java8 + SpringBoot2.7 + MySQL8 + Redis,后端源码清爽易扩展
java·后端·源码·springboot·mes系统·源码二开·mes源码
JAVA社区1 小时前
Java高级全套教程(十)—— SpringCloudAlibaba超详细实战详解
java·开发语言·spring cloud·面试·职场和发展
金銀銅鐵1 小时前
[Java] 如何理解 class 文件中方法的 descriptor?
java·后端
云烟成雨TD2 小时前
Spring AI Alibaba 1.x 系列【63】AI Agent 长期记忆
java·人工智能·spring
憧憬成为java架构高手的小白2 小时前
苍穹外卖--day09
java·spring boot·百度
学代码的真由酱2 小时前
Java多用户一对一网页聊天室-测试报告
java·开发语言·功能测试·测试
Jasonakeke3 小时前
SpringBoot自动配置原理揭秘
java·spring boot·后端
2301_803538953 小时前
Java读取Word图片的两种实用方法
java·开发语言·word