天天看点

迭代器并发修改异常ConcurrentModificationException

我们知道,使用迭代器遍历集合时,如果进行增删等操作,会抛出一个异常:ConcurrentModificationException并发修改异常,那么为什么会这样呢?一起来研究研究

迭代器并发修改异常ConcurrentModificationException

如下,迭代时对集合coll进行删除操作,异常抛出

Iterator<Integer> it = coll.iterator();

        while (it.hasNext()) {
            int s = it.next();
            coll.remove(s);//执行该操作上面的next()会抛出ConcurrentModificationException并发修改异常
            System.out.println(s);
        }
           

我们寻找控制台的信息进入java.util.ArrayList$Itr.next(ArrayList.java:893)

迭代器并发修改异常ConcurrentModificationException

发现在next方法中,有一个checkForComodification();方法,我们点进去查看里面都做了些什么。

迭代器并发修改异常ConcurrentModificationException

是不是很熟悉,在if判断中抛出了这个并发修改异常,那你可能会好奇了,这个modCount和expectedModCount又是什么东西呢?

字面意思我们先大概理解一下,mod,是modification的简写,修改的意思,expected:期望的,这时我们可能就会想到:噢,修改值和期望值

也就是说在迭代时,调用next方法,会调用checkForComodificatio()进行判断,如果修改值和期望值不一致,就抛出并发修改的异常。

我们继续Ctrl点modCount找到它的位置,发现在AbstractList中628行定义它,初始化为0

迭代器并发修改异常ConcurrentModificationException
迭代器并发修改异常ConcurrentModificationException

再看expectedModCount,创建时会把modCount的值赋值给它

迭代器并发修改异常ConcurrentModificationException

而这两个变量,modCount是在集合中,expectedModCount在接口中,换句话说:创建集合时会定义变量modCount,默认为0,创建迭代器时将定义expectedModCount并将modCount当前的值赋值给它

我们继续往下看,诶?

迭代器并发修改异常ConcurrentModificationException

当我们调用集合的add方法时,modCount会自增,同理,调用remove方法时,也会自增(其他一些方法同理)

迭代器并发修改异常ConcurrentModificationException

到这里,我们举一个简单的例子来说明一下整个流程:

1.现在我创建一个ArrayList list,此时modCount为0,然后我进行4次添加操作,list.add(1),此时modCount的值为4

2.然后我创建迭代器,Iterator it = list.iterator();

此时会将modCount的值赋值给expectedModCount****,expectedModCount现在也为4

3.紧接着我使用while循环来开始遍历list

while (it.hasNext()) {

int s = it.next();

list.remove(s);

System.out.println(s);

}

4.遍历时抛出了异常,这里调用remove(s)时,modCount++,由4变成了5,上面我们讲过,next方法中会调用checkForComodificatio方法判断modCount和expectedModCount的值是否相等,不相等就会抛出异常,此时modCount为5,expectedModCount为4,下次循环到next方法,异常就抛出了

那该如何解决呢?我们直接上答案,使用ListIterator lit = list.listIterator();创建迭代器,用lit的add或remove来进行增删,你可能会想wtf?为毛这个就可行了!

别急,我们再一起到源码中找答案

迭代器并发修改异常ConcurrentModificationException
迭代器并发修改异常ConcurrentModificationException

是不是瞬间就明白了,这里的add方法中加上了一个同步操作,让modCount和expectedModCount始终保持一致,所有就不会抛出该异常了。

over

楼主是一只萌新,如有错误之处还望大家指正