Java集合中迭代器遍历过程的并发修改异常问题(Debug模式追踪)
我们在使用迭代器Iterator遍历集合中元素的过程中修改集合中元素的操作会抛出一个并发修改异常: ConcurrentModificationException, 这里以debug模式查看其代码执行过程是怎么触发这个异常的。
首先先来看一下代码:
public class ListDemo2 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
//添加一个元素
list.add("hello");
// list.add("world");
// list.add("java");
// list.add("python");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
if (s.equals("hello")) {
list.remove("hello");
}
}
System.out.println(list);
}
}
案例源码追踪过程:
在代码中,先添加一个元素,然后使用迭代器遍历的过程中,对list中元素进行删除,此时看看debug模式代码如何执行。
添加元素后,size = 1
迭代器初始化了expectedModCount = modCount = 1; 因为一开始的add("hello")时 , modCount已经进行+1操作。
接着下一步进入循环条件判断是否有下一个元素: 可以看到此时cursor != size. 所以执行循环体。
执行iterator.next(),然后需要先执行checkForComodification();
就是为了确认修改次数modCount 与 预期的修改次数是否一致,不一致则抛出并发修改异常,此时一致正常执行
此时游标cursor+1 = 1,并把数组中第0个元素也就是“hello”返回。
接着将返回的“hello”与 “hello”字符串进行比较,相等则调用remove() 删除list中的hello,进入remove()方法
调用remove()方法,找到需要删除的元素后最终调用的是fastRemove();进入fastRemove(),我们会发现此时modCount++,因为这里删除元素使得modCount修改次数+1. 此时modCount = 2 , expectedModCount = 1.
这时remove()已经执行,元素被删除,size的值已经变为0.
在第二次进行循环条件判断时,进入hasNext()方法
此时cursor != size ,返回true.则再次进行循环体中执行iterator.next()方法,也就需要再次执行checkForComodification();
此时modCount = 2 , expectedModCount = 1,抛出并发修改异常! 全部过程跟踪完毕!
总结抛出并发修改异常的原因:就是add(),remove()方法每次执行都会使modCount++, 而如果在迭代器使用的过程中进行修改数据,modCount++ , 但是expectedModCount还是原来初始化的值,最终两者值不同,抛出并发修改异常。
需要注意的是:在写以下demo时并没有抛出并发修改异常:
其实内部modCount != expectedModCount,因为迭代器遍历过程有一次删除操作,modCount++,不抛出异常是因为刚好在判断条件iterator.hasNext()时,cursor == size , 自然没有进入循环体执行iterator.next(),也就没有执行checkForComodification();没有抛出异常。
本文地址:https://blog.csdn.net/Best_CXY/article/details/107873730