项目中用了集合的subList方法,然后又size一下。后来跑起来的时候报异常:ConcurrentModificationException。第一次遇见这个异常,仅从字面意思上以为和多线程并发有关系,但是仔细想想,发生异常的代码并不会出现多线程并发问题。经过查找资料,并且看了相关源码才明白其中原理。
集合中出现ConcurrentModificationException异常被称为集合的fail-fast机制。这样机制主要用来检测集合修改前是否已经被修改,确保在多线程中数据保证一致性。很多人说是因为多线程并发导致该异常,其实不完全是,我这里出现异常就是在单线程中发生。
出现ConcurrentModificationException异常主要是因为调用集合内部调用checkForComodification方法。方法内容
private void checkForComodification() {
if (l.modCount != expectedModCount)
throw new ConcurrentModificationException();
}
当出现modCount!=expectedModCount时候就会异常。
1.当有多个线程操作一个集合时,一个线程iterable便利,另一个线程增加或者删除,只要改变原来集合数量。这样情况下回发生ConcurrentModificationException。因为集合iterator方法后会返回一个内部类Itr(),该方法的next,remove,previous方法中都有checkForComodification()方法。内容同上代码。Itr内部类的expectedModCount是直接来自AbstractList字段modCount,modCount字段就是原集合中字段。所以,一旦原集合变化但是生产Itr(即迭代器)modCount没有一起发生变化才导致这样问题。
2.当有且只有一个线程情况下,不存在多并发下操作线程时,使用subList方法后然后,对原list集合操作(新增一个,删除一个或者清除全部),最后在调用子集合中size,或者别的有checkForComodification方法的方法时也会发生异常.subList在AbstractList中实现是如下代码
public List<E> subList(int fromIndex, int toIndex) {
return (this instanceof RandomAccess ?
new RandomAccessSubList<E>(this, fromIndex, toIndex) :
new SubList<E>(this, fromIndex, toIndex));
}
在SubList构造函数中代码如下
SubList(AbstractList<E> list, int fromIndex, int toIndex) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > list.size())
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
l = list;
offset = fromIndex;
size = toIndex - fromIndex;
expectedModCount = l.modCount;
}
构造函数中l.modCount就是this参数的modCount,即原函数的modCount.所以一旦subList调用以后,然后再处理原集合内容,改变modCount,则很容易发生ConcurrentModificationException异常,并且该异常不是并发导致。
参考文献:http://www.cnblogs.com/skywang12345/p/3308762.html#a3