(一) 什么是fail-fast?
fail-fast是java集合的一种错误机制,当多个线程并发访问集合时,就有可能产生fail-fast事件,抛出ConcurrentModificationException异常。
(二) fail-fast如何产生?
当一个线程对集合进行结构性的修改(如添加,删除,清空元素)时,而另一个线程访问集合,此时,expectedModCount 与 modCount不相等就会抛出ConcurrentModificationException异常。
以ArrayList的代码为例:
当用迭代器遍历ArrayList的集合时:
List<Integer> list = new ArrayList<>();
Iterator it = list.iterator();
调用的是ArrayList中的iterator()方法:
public Iterator<E> iterator() {
return new Itr();
}
而Itr是ArrayList中的一个内部类,实现了Iterator接口:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
//...其他代码略
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
从上面代码可以发现,每次调用ArrayList的iterator()方法都将产生一个Itr实例,而每个Itr实例都有自己的 expectedModCount ,而 modCount 是ArrayList的属性。假如一个线程A调用了ArrayList的iterator()方法,此时expectedModCount = modCount。此后,在线程A遍历ArrayList的过程中,另一个线程B对ArrayList做了结构性修改, modCount +1 了,此时线程A的expectedModCount仍然是原来的值,代码中一判断modCount != expectedModCount,于是ConcurrentModificationException异常就被抛出了。
(三) 如何避免fail-fast?
使用并发集合代替,比如用CopyOnWriteArrayList代替ArrayList。