快速失败是指某个线程在迭代集合类的时候,不允许其他线程修改该集合类的内容,这样迭代器迭代出来的结果就会不准确。
比如用iterator迭代collection的时候,iterator就是另外起的一个线程,它去迭代collection,如果此时用collection.remove(obj)这个方法修改了collection里面的内容的时候,就会出现ConcurrentModificationException异常,这时候该迭代器就快速失败。
代码如下:
package com.vino.assemble; import java.util.ArrayList; import java.util.List; /** * show fail fast in in the hashmap * @author haowei.yu * */ public class FailFastDemo { public static void main(String[] args) { List<Integer> tempList = new ArrayList<Integer>(); tempList.add(1); tempList.add(2); tempList.add(3); tempList.add(4); tempList.add(5); tempList.add(1); //use iterator to travel the list and remove the value equals to 1 for(int temp: tempList){ if(temp == 1){ tempList.remove(temp); } } } }
这样运行程序,就会抛出java.util.ConcurrentModificationException异常。
这样做的好处是:对于非并发集合,在用迭代器对其迭代时,若有其他线程修改了增减了集合中的内容,这个迭代会马上感知到,并且立即抛出 ConcurrentModificationException 异常,而不是在迭代完成后或者某些并发的场景才报错。具体这样的机制在java里是怎么实现的呢?其实很简单,是通过modCount域来实现的。modCount顾名思义是修改次数,对List内容的修改都会增加这个值,在迭代器初始化的过程中会将这个值赋值给迭代器的expectedModCount。我们来看ArrayList和Iterator的源码,注释已经写的听清楚了,这里就不解释了。
//ArrayList的源码 protected transient int modCount = 0; //In AbstractList class,provider fail-fast iterators.note that this field is transient public boolean add(E e) { modCount++; // Increments modCount!! ..... return true; } public E remove(int index) { .... modCount++; // Increments modCount!! .... return oldValue; } //Iterator的源码 int expectedModCount = modCount; // iterator believes the backing list should hava. public void remove() { try { .... if (modCount != expectedModCount)// judge the modCount equals with expectedModCount. throw new ConcurrentModificationException(); ... } }
TIPS:
arrayList里的快速失败,布布扣,bubuko.com
原文:http://www.cnblogs.com/babybluevino/p/3695948.html