快速失败策略(fail - fast)
即为优先处理产生异常的情况,当异常情况发生时,直接向用户抛出异常,程序终止。
例:
public static int div(int a,int b){
if (b == 0){
throw new IllegalArgumentException("除数不能为0");
}
return a / b;
}
当我们执行这种代码的时候会出现如下情况:
public class ListIteratorTest2 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
//modcount = 1
list.add("hello");
//modcount = 2
list.add("java");
//modcount = 3
list.add("hello");
//modcount = 4
list.add("fwb");
// expectedModCount = modcount (4)
Iterator<String> iterator = list.iterator();//取得迭代器
while(iterator.hasNext()){
String str = iterator.next();
if (str.equals("fwb")){
list.remove(str);
//modcount++(5)
}
System.out.println(str);
}
}
}
java.util.ConcurrentModificationException,产生原因:当迭代输出集合时,并发修改了集合的结构。
源码中的 protected transient int modCount 记录了当前集合被修改的(add,remove等方法)次数。.
源码中当使用迭代器的时候,会执行这样一个代码int expectedModCount = modCount;
以及这个方法:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
当我们执行: list.remove(str);这行代码的时候 modCount++,则modCount != expectedModCount,产生了异常,之所以前四个可以正常输出是因为在remove之后modcount才加1,所以在此之前都是正常的。(见代码)
意义:例如有3个线程在同时运行,2个线程在读取ArrayList的内容,1个线程修改了该集合的值,那么这两个线程读取的内容就有可能是不正确的。fail—fast机制保证集合在多线程场景下读到最新的值。 java.util 的集合类大多都采用此策略(如:ArrayList、Vector、LinkedList、HashSet,读写都在同一个副本中)
与其相关的有:
fail—safe:
java.util.concurrent:CopyOnWriteArrayList/conCurrentHashMap
CopyOnWriteArrayList采用读写分离,所有的读为异步操作,写为同步操作,且读写不在同一个副本。
如何处理:
1.迭代输出的时候,不要修改集合的内容
2.使用迭代器的修改方法(在源码中,他虽然最终调用的还是ArrayList的方法。但是在此之后将expectModCount重新赋值了一次)
if (str.equals("fwb")){
//list.remove(str);
iterator.remove();
}