ConcurrentModificationException出现的原因以及解决办法(JDK1.7)
ConcurrentModificationException 异常出现的原因
- 首先看如下代码
1 | public class T{ |
从异常信息来看,异常发生在ArrayList内部类的Itr的checkForComodification()方法中。
那我们从程序的 Iterator<String> it = list.iterator();
开始,进入源码如下:
1 | public Iterator<E> iterator(){ |
从上面代码可以看出,返回的是一个Itr对象,再次寻找发现,Itr为ArrayList的内部类。具体代码如下:
1 | /** |
首先解释几个变量的含义cursor
游标,表示下一个要访问的元素索引lastRet
表示上一个访问的元素索引expectedModCount
表示对ArrayList修改次数的期望值,初始值等于modCountmodCount
是AbstractList的成员变量,表示对ArrayList修改的次数,在add以及remove、clear等方法中可以看出。初始值为0
还是看上面那个程序,当程序执行到while
语句时,其实是执行Itr类的hasNext方法,根据此方法可知,cursor为0,size为1,返回true
注意此时 expectedModCount的值为0,接着执行next方法,返回第一个对象,即值为”aa”的字符串,此时cursor的值为1,执行if判断之
后执行remove方法,注意此时是ArrayList中的remove方法,下面看看remove方法。
1 | public boolean remove(Object o) { |
从以上代码可知,最终执行的代码是fastRemove,执行完此方法之后,modCount的值为1,size的值为0
再次执行while的hasNext方法时,cursor的值为1,size的值为0,返回true,接着执行next方法,
此时,modCount=1,而expectedModCount的值为0,故抛出ConcurrentModificationException异常。
关键点是:remove方法修改了modCount的值,使得modCount与expectedModCount的值不一致引起的。
即使是for循环的形式也抛出此异常。
ConcurrentModificationException 异常的解决办法
既然知道了原因,那怎么解决呢?
细心的同学可能发现Itr类中也存在remove方法,此方法其实也是调用的list.remove方法,但是此方法多了一行代码
1 | expectedModCount = modCount; |
因此在迭代中删除元素时,使用Itr的remove方法。代码修改为:
1 | public class Test{ |
在单线程下,代码修改为如下代码没有问题,但是不适合多线程情况。多线程解决方案是使用CopyOnWrite来代替ArrayList