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

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

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被别的线程修改,导致出现的问题

相关推荐
小梁努力敲代码2 小时前
java数据结构--List的介绍
java·开发语言·数据结构
摸鱼的老谭3 小时前
构建Agent该选Python还是Java ?
java·python·agent
lang201509283 小时前
Spring Boot 官方文档精解:构建与依赖管理
java·spring boot·后端
夫唯不争,故无尤也3 小时前
Tomcat 启动后只显示 index.jsp,没有进入你的 Servlet 逻辑
java·servlet·tomcat
zz-zjx3 小时前
Tomcat核心组件全解析
java·tomcat
Deschen3 小时前
设计模式-外观模式
java·设计模式·外观模式
007php0074 小时前
百度面试题解析:微服务架构、Dubbo、Redis及其一致性问题(一)
redis·百度·docker·微服务·容器·职场和发展·架构
why技术4 小时前
从18w到1600w播放量,我的一点思考。
java·前端·后端
夫唯不争,故无尤也4 小时前
JavaWeb流式传输速查宝典
java·流式传输
苏小瀚5 小时前
算法---位运算
java·算法