标签:style blog http io ar os 使用 sp java
Java在操作ArrayList、HashMap、TreeMap等容器类时,遇到了java.util.ConcurrentModificationException异常。以ArrayList为例,如下面的代码片段:
执行上述代码后,报错如下:
在第21行报错,即it.next(),迭代器在获取下一个元素时报错。找到java.util.ArrayList第830行,看到it.next()的源代码,如下:
调用了checkForComodification()方法,代码如下:
即,比较modCount和expectedModCount两个是否相等。modCount是ArrayList从AbstractList继承来的属
性,查看modCount属性的doc文档,可知,modCount表示列表(list)被结构性修改(structurally
modified)的次数。structurally
modified是指造成列表中元素个数发生变化的操作,ArrayList中的add,addAll,remove,
fastRemove,clear, removeRange, ensureCapacity,
ensureCapacityInternal,
ensureExplicitCapacity等方法都会使modCount加1,而batchRemove,removeAll,retainAll
等方法则根据删除的元素数增加modCount的值(removeAll和retainAll都是调用batchRemove实现,具体modCount
的修改算法还需研究)。
第一个代码片段中的操作方式1和操作方式2都是采用了迭代器的方式。当使用 iterator方法得到Iterator对象(或者使用listIterator获得ListItr对象),其实是返回了一个Iterator接口的实 现类ArrayList$Itr(继承自AbstractList$Itr),该类为ArrayList的一内部类,该类中有一个 expectedModCount字段,当调用ArrayList$Itr的next方法时,会先检查modCount的值是否等于 expectedModCount的值(其实在调用next, remove, previous, set, add等方法时都会检查),不相等时就会抛出java.util.ConcurrentModificationException异常。
为什么会抛出该异常呢?从代码可以看到调用了6次add方法,这时modCount的 值也就为6,当当使用iterator方法得到Iterator对象时把modCount的值赋给了expectedModCount,开始时 expectedModCount与modCount是相等的,当迭代到第二个元素(index=1)“string2”时,因为if条件为true,于 是又调用了remove方法,调用remove方法时modCount值又加1,此时modCount的值为7了,而expectedModCount的 值并没有改变,当再次调用ArrayList$Itr的next方法时检测到modeCount与expectedModCount不相等了,于是抛出异 常。
当把if语句写成if(s.equals("string5"))时又没有抛出该异
常,这又是为什么呢?ArrayList$Itr中还有一个名为cursor的字段用来指向迭代时要操作的元素索引,初始值为0,每调用一次next方法
该字段值加1,注意是先从集合中取出了元素再加1的。当判断"string5"时,注意是倒数第二个元素,这些cursor的值为5,移除掉元
素"string5"时,List的size为5,当调用ArrayList$Itr的hasNext方法判断有无下一个元素时,判断的依据为
cursor的值与size是否相等,不相等则还有下一个元素,而此时两者值刚好相等,也就没有往下执行next方法了,也就没有抛出异常,因此删掉倒数
第二个元素时不会抛异常的异常。
解决方案有四种,直接看第一段代码即可。
java.util.ConcurrentModificationException异常分析
标签:style blog http io ar os 使用 sp java
原文地址:http://www.cnblogs.com/yuyanbian/p/4114553.html