快速失败(fail-fast)和安全失败(fail-safe)

序言

我们有这种场景,比如对Java集合类进行遍历,但是在遍历过程中对集合进行修改(增加、删除、修改),这里会抛出Concurrent Modification Exception。
原因:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。
注意:异常的抛出条件是检测到 modCount!=expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。

  1. 快速失败:
    java.util包下面的所有的集合类都是快速失败的。快速失败的迭代器会抛出ConcurrentModificationException异常。当在迭代一个集合的时候,如果有另外一个线程在修改这个集合,就会抛出ConcurrentModification异常。不能在多线程下发生并发修改。
    查看ArrayList源代码,在next方法执行的时候,会执行checkForComodification()方法
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
        final void checkForComodification() {
            if (modCount != expectedModCount)   //如果modCount和expectedModCount不相等,则抛出异常
                throw new ConcurrentModificationException();
        }
  1. 安全失败:
    java.util.concurrent包下面的所有的类都是安全失败的。Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。

参考:https://blog.csdn.net/qq_31780525/article/details/77431970

你可能感兴趣的:(快速失败(fail-fast)和安全失败(fail-safe))