Iterator迭代器遍历过程出现ConcurrentModificationException的原因
一、情况一
遍历的过程,使用List集合的remove方法删除某个元素,使size的值发生变化,导致 hasNext成立,从而在进行下一步的ite.next()时执行checkForComodification()方法,检查出modCount != expectedModCount成立,最后抛出throw new ConcurrentModificationException()异常。
二、调试源码核心变量的变化过程如下
补充:
list集合只添加了2个元素,为什么会遍历第三次呢?
这是因为在遍历第2遍的时候,list.remove()改变了list的size成员变量的大小,使size=1,导致迭代器iterator在判断是否还有下一个元素hasNext()时,cursor=2不等于siez=1成立,进入了第三次循环。
三、调式源码详细过程如下
步骤1、首先Debug来到ite.hasNext();
步骤2、接着F9(resume program)运行到下个断点处。
说明,步骤1中添加了2个元素,所以list的size=2;并且索引是从0开始的,所以cursor=0。
步骤3、接着F9(resume program)运行到下个断点处ite.next();
步骤4、接着F9(resume program)进入到下个断点处next()源码;
步骤5、接着F9(resume program)进入到下个断点处checkForComodification()源码;
modCount表示修改,添加集合的次数。
expectedModCount表示获取迭代器时修改次数的初始站,是在获取Iterator时赋值的。关于expectedModCount如下图所示。
那现在可以看到在next()源码中首先会对modCount和expectdModCount进行检查。
步骤6、接着F9(resume program)进入到下个断点处return (E) elementData[lastRet = i];
返回elementData[0]处的元素,也就是list中的第一个元素“e1"。
步骤7、接着F9(resume program)回到main方法的下个断点处;
if (element.equals(“e2”)){}条件不成立,接着执行while(ite.hasNext()){}循环。
步骤8、接着F9(resume program)回到main方法的while(ite.hasNext());
接着重复步骤2、执行F9(resume program)运行到下个断点处。此时的cursor=1.
hasNext()条件成立,返回true;
重复步骤3、接着F9(resume program)运行到下个断点处ite.next();
重复步骤4、接着F9(resume program)进入到下个断点处next()源码;
重复步骤5、接着F9(resume program)进入到下个断点处checkForComodification()源码;
重复步骤6、接着F9(resume program)进入到下个断点处return (E) elementData[lastRet = i];
返回elementData[1]处的元素,也就是list中的第一个元素“e2"。
重复步骤7、接着F9(resume program)回到main方法的下个断点处;
if (element.equals(“e2”)){}条件成立,接着执行list.remove(”e2“);
步骤9、接着F9(resume program)进入remove源码的断点处;
这一步modCount++;执行F8(Step Over),到下一步。
可以看到modCount=3,由前面mian方法开始时添加e1,e2两个元素是moumodCount=2;然后list.iterator(),对expectedModCount初始值moumodCount=2;
步骤9、接着F9(resume program)回到main方法ite.hasNext()断点处;
接着重复步骤2、执行F9(resume program)运行到下个断点处。此时的cursor=1.
调试过程的关键点就在这了,正常来说,已经没有下一个元素的,hasNext应该返回false。但由于调用了list.remove(),导致size减1,变成1,初始hasNext()中的条件返回true。
重复步骤3、接着F9(resume program)运行到下个断点处ite.next();
重复步骤4、接着F9(resume program)进入到下个断点处next()源码;
重复步骤5、接着F9(resume program)进入到下个断点处checkForComodification()源码;
可以看到,由于list.remove()方法导致modCount加1,此时的expectedModCount还是初始化时的2,导致条件成立,抛出throw new ConcurrentModificationException();
最后
调式到这里,就可以看到抛出ConcurrentModificationException异常的全过程和原因了。
—end
补充:学习使用iterator通过打断点调式jdk源码的来源链接如下:
https://www.iqiyi.com/v_19rwo3zlac.html#curid=14761082600_3ec318964b26c62b687013f50d84974c