部分内容参考自:http://www.cnblogs.com/skywang12345/p/3308762.html
- fail-fast 定义
fail-fast(快速失败)机制:是Java集合中Iterator的一种检错机制。
当某个线程用iterator对list进行遍历时,其他线程同时并发的对list进行插入或者删除等操作,使得list产生了结构性的变化(结构性变化是指:list的size被改变的一些变化),就会抛出ConcurrentModificationException,Iterator产生fail-fast行为,使自己快速失效,以避免自己去冒险,去经历未来不确定时刻的不确定因素,这也是fail-fast机制的目的。
注意1,只有add,remove,clear等操作能使得list的size发生改变,而set等操作没有使得list的size产生变化,因此,只有前者的相关操作可以使得list产生结构性的变化。
注意2,并非所有插入删除等操作都能产生fail-fast行为。如果使用Iterator内部的插入删除就不会,原因见后。除此之外都能产生fail-fast行为。
举个例子:当线程A正在用iterator遍历list时,线程B同时用LinkedList中的add()并发的向list中插入了元素,使得list产生了结构性的改变,这时会抛出ConcurrentModificationException,Iterator失效。
- fail-fast 原理
fail-fast的原理基于两个变量 modCount 和 expectedModCount ,首先介绍一下modCount变量:
在AbstractList中定义了一个非static的全局变量modCount(一个对象拥有一个该变量),AbstractList的子类自然也会拥有自己的modCount,比如:ArrayList,LinkedList,Vector等都是该类的子类。当某个集合产生了结构性的变化时,该集合所持有的modCount就会加一。Iterator类中的add()等方法也会使modCount加一。
接下来是expectedModCount变量:
expectedModCount变量是定义在每个子类的内部类ListIterator中的,当Iterator被创建后,expectedModCount初始化为modCount。这里需要注意的是,expectedModCount值不是一成不变的。当调用Iterator中的插入删除等方法改变了list的size时,expectedModCount值会同modCount值一起加一,与modCount值保持一致。而调用外部类的插入删除等方法时,就只有modCount值会加一,expectedModCount值就不变,这两个变量就不相等了。
fail-fast的原理:
在调用iterator中的next(),previous()等方法时,首先会去比较一下当前modCount和expectedModCount值,如果这两个值不相等,说明:在遍历期间,有其他线程修改了正在遍历的这个集合,并使得该集合产生了结构性的变化,而且Iterator并不知道其他线程都对list做了哪些修改,这个对Iterator来说是很危险的。故,这个时候就该抛ConcurrentModificationException异常,Iterator产生了fail-fast行为,使自己快速失效。这也就说明了为什么Iterator内部的插入删除操作不会产生fail-fast行为,因为这些修改过程是Iterator知道的,它能在修改的过程中去修改一些指针来使自己能够适应这些修改。