Fail-Fast机制详解

  Java中的Iterator非常方便地为所有的数据源提供了一个统一的数据读取(删除)的接口,但是在使用的时候容易报如下错误ConcurrentModificationException,原因是在使用迭代器时候底层数据被修改,最常见于数据源不是线程安全的类,如HashMap & ArrayList等。如下代码所示:

public class FailFastDemo {
public static void main(String[] args)throws Exception {
List<Object> objects = new ArrayList<Object>();
objects.add("object1");
objects.add("object2");
objects.add("object3");
Iterator<Object> iterator = objects.iterator();
while (iterator.hasNext()) {
Object object = iterator.next();
System.out.println(object);
objects.remove(object);
}
}
}

产生原因

  Java中的集合类分为两种类型:线程安全,位于java.util.concurrent命名目录下,如CopyOnWriteArrayList;线程不安全:位于java.util目录下,如ArrayList,HashMap。所谓线程安全是在多线程环境下,这个类还能表现出和行为规范一致的结果。既然有线程安全的集合,为什么还要使用线程非安全的集合呢呢?因为线程安全的类通常需要通过各种手段去保持对数据访问的同步,会降低数据访问的效率。使用非线程安全的集合类在非并发场景具有很大的优势。如果开发者在使用时没有注意,将非线程安全的集合类用在了并发的场景下,比如线程A获取了ArrayList的iterator,然后线程B通过调用ArrayList.add()修改了ArrayList的数据,此时就有可能会抛出ConcurrentModificationException。
  原理很简单,构建Iterator时将当前ArrayList的modCount保存在expectedModCount之中 ,当下一次调用next()时,会判断ArrayList的modCount值和iterator内部expectedModCount保存的值是否相等。如果相等,说明在遍历的过程中集合类内有发生改变;如果不相等说明在遍历的过程中,集合中的数据发生了改变此时就抛出ConcurrentModificationException。fast-fail是JDK为了提示开发者将非线程安全的类使用到并发的场景下时,抛出一个异常,及早发现代码中的问题。
补充:
  fast-fail的Iterator本身也提供了remove()来删除当前遍历到的元素,例如:ArrayListIterator中的remove(),可以在迭代过程中删除当前数据而不抛出ConcurrentModificationException:

public class FailFastDemo {
public static void main(String[] args)throws Exception {
List<Object> objects = new ArrayList<Object>();
objects.add("object1");
objects.add("object2");
objects.add("object3");
Iterator<Object> iterator = objects.iterator();
while (iterator.hasNext()) {
Object object = iterator.next();
System.out.println(object);
iterator.remove();
}
}
}
上一篇:Atitit oodbms的查询,面向对象的sql查询jpa jpql hql


下一篇:Rlwrap工具的安装和配置