在多线程下使用Iterator来迭代对象时,总会包ConcurrentModificationException();异常,经过我对list和Iterator相关源码的分析,终于搞明白了这个问题:
下面结合源代码来讨论这个问题:
1、当我们调用一个List的iterator时,其实返回的并不是Itr对象(Iterator是一个接口),请看代码:
1
publicIteratoriterator(){2returnnewItr();3 }
2、在Itr类中有这么一句话 int expectedModCount = modCount;首先讲一下这两个变量的含义:
expectedModCount :创建当前的Itr对象时集合对象被修改的次数。他是Itr的变量。
modCount:记录集合对象从创建到当前时间被做修改的次数。(集合每进行一次增删改查都会使modCount),他是Itr的外部类AbstractList
的变量,且该变量在 AbstractList中被如此修饰protected transient int modCount = 0;
另外,Itr自己对集合对象进行了修改后,他会维持expectedModCount 和modCount的保持相等,请看以下代码
1 //Itr的删除方法2 publicvoidremove() {3 if(lastRet==-1)4 thrownewIllegalStateException();5checkForComodification();67 try{8 AbstractList.this.remove(lastRet);9 if(lastRet
在代码的12行,Itr保证了expectedModCount 和modCount值的相等 ,modCount的值发生了改变吗,他改变了,带代码的第8行改变的,请看此处的代码:
1
publicE remove(intindex){2 RangeCheck(index);34 modCount++;5 E oldValue=elementData[index];67intnumMoved=size-index-1;8if(numMoved>0)9 System.arraycopy(elementData, index+1, elementData, index,10 numMoved);11 elementData[--size]=null;//Let gc do its work1213returnoldValue;14 }
在代码的第四行modCount发生了改变。 由此可以看出,在我们调用集合对象的iterator()方法的remove时总会使list的modCount的值自增1,但是Itr会自己维护该值和expectedModCount 的一致。
3、试问:如果expectedModCount 和modCount的值如果不相等,会有什么问题呢,这就是报ConcurrentModificationException();异常的原因所在,请先看Itr的next()方法和next()调用的方法
1
//Itr的next方法:2
publicE next(){3 checkForComodification();4
try{5 E next=get(cursor);6 lastRet=cursor++;7returnnext;8
}catch(IndexOutOfBoundsException e){9 checkForComodification();10thrownewNoSuchElementException();11 }12 }1314//checkForComodification()方法:15
finalvoidcheckForComodification(){16if(modCount!=expectedModCount)17thrownewConcurrentModificationException();18 }19 }20
在next方法的一开始显示调用了checkForComodification()方法(见第三行),在checkForComodification()方法中做的工作就是比较expectedModCount 和modCount的值是否相等,如果不相等,就认为还有其他对象正在对当前的List进行操作,那个就会抛出ConcurrentModificationException异常。
经过以上的分析,发现抛出ConcurrentModificationException异常处于调用next()方法时,比较expectedModCount 和modCount的值,如果两个值不相等,就会抛出异常,然而在什么情况下会使expectedModCount 和modCount的值不相等呢,只有在两个Itr同时对一个list进行操作的时候才会出现这样的问题,所以在以后的编码过程中在是由Iterator进行remove()时一定要考虑是否时多线程的,如果是请不要用Iterator进行remove(),而应该使用List的remove方法进行。