我们知道,使用迭代器遍历集合时,如果进行增删等操作,会抛出一个异常:ConcurrentModificationException并发修改异常,那么为什么会这样呢?一起来研究研究
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL5IDN3IDN1ETM2AjMxgTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
如下,迭代时对集合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)
发现在next方法中,有一个checkForComodification();方法,我们点进去查看里面都做了些什么。
是不是很熟悉,在if判断中抛出了这个并发修改异常,那你可能会好奇了,这个modCount和expectedModCount又是什么东西呢?
字面意思我们先大概理解一下,mod,是modification的简写,修改的意思,expected:期望的,这时我们可能就会想到:噢,修改值和期望值
也就是说在迭代时,调用next方法,会调用checkForComodificatio()进行判断,如果修改值和期望值不一致,就抛出并发修改的异常。
我们继续Ctrl点modCount找到它的位置,发现在AbstractList中628行定义它,初始化为0
再看expectedModCount,创建时会把modCount的值赋值给它
而这两个变量,modCount是在集合中,expectedModCount在接口中,换句话说:创建集合时会定义变量modCount,默认为0,创建迭代器时将定义expectedModCount并将modCount当前的值赋值给它
我们继续往下看,诶?
当我们调用集合的add方法时,modCount会自增,同理,调用remove方法时,也会自增(其他一些方法同理)
到这里,我们举一个简单的例子来说明一下整个流程:
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?为毛这个就可行了!
别急,我们再一起到源码中找答案
是不是瞬间就明白了,这里的add方法中加上了一个同步操作,让modCount和expectedModCount始终保持一致,所有就不会抛出该异常了。
over
楼主是一只萌新,如有错误之处还望大家指正