首页 > 试题广场 >

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

[问答题]
快速失败(fail-fast)和安全失败(fail-safe)的区别是什么?
lterator的安全失败,是基于对底层集合拷贝进行的,在集合的增删的时候对迭代没有影响。而java.util.concurrent是基于安全失败的。java.util下的集合都是基于快速失败的
编辑于 2018-04-23 22:24:12 回复(0)
更多回答

一:快速失败(fail—fast)

          在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加、删除、修改),则会抛出Concurrent Modification Exception。

          原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。

      注意:这里异常的抛出条件是检测到 modCount!=expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。

      场景:java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)。

    二:安全失败(fail—safe)

      采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。

      原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception

      缺点:基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。

          场景:java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。

发表于 2017-07-22 12:37:22 回复(9)
快速失败:当你在迭代一个集合的时候,如果有另一个线程正在修改你正在访问的那个集合时,就会抛出一个ConcurrentModification异常。
    在java.util包下的都是快速失败。
安全失败:你在迭代的时候会去底层集合做一个拷贝,所以你在修改上层集合的时候是不会受影响的,不会抛出ConcurrentModification异常。
    在java.util.concurrent包下的全是安全失败的。
发表于 2016-12-09 17:08:27 回复(2)

快速失败是直接对原集合遍历的,数据修改后可能抛出异常,而安全失败是对原集合的拷贝遍历的,不会抛出异常。

发表于 2020-02-27 21:09:59 回复(1)
快速失败只是一种直译,它不是音译,但,近似与意译。   就如同手机一样,并不是只有拿在手里才能用,放在兜里,它照样能用。   java中快速失败是指某个线程在迭代vector的时候,不允许其他线程修改该vector的内容。   这样迭代器迭代出来的结果就会不准确,如用iterator迭代collection的时候,iterator就是另外起的一个线程,它去迭代collection,如果此时用collection.remove(obj)这个方法修改了collection里面的内容的时候,就会出现ConcurrentModificationException异常,这时候该迭代器就快速失败。 向量的概念 向量(Vector)是java.util包提供的一个用来实现不同类型元素共存的变长数组的工具类。 Vector类的对象(不能是简单数据类型)不但可以保存顺序的一列数据,而且还封装了许多有用的方法来操作和处理这些数据,比数组功能强大。 适合用Vector类的情况: (1)需要处理的对象数目不定,序列中的元素都是对象,或可以表示为对象; (2)需要将不同类的对象组合成一个数据系列; (3)需要做频繁的对象序列中元素的插入和删除; (4)经常需要定位序列中的对象或其他查找操作; (5)在不同类之间传递大量的数据。 向量的概念
编辑于 2016-04-16 15:36:56 回复(3)
区别1:安全失败是基于对底层集合的拷贝,不受源集合上的修改。 区别2:快去失败抛出特有异常,ConcurrentModicationException,安全失败是不会抛出快速失败的特有异常 区别3:java.util包下都是快速失败,java.util.concurrent包下都是安全失败
发表于 2016-10-17 15:37:26 回复(0)
快速失败和安全失败的区别 Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。 java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。 快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常。 所以,我还是不知道什么意思。 区别1:安全失败是基于对底层集合的拷贝,不受源集合上的修改。 区别2:快去失败抛出特有异常,ConcurrentModicationException,安全失败是不会抛出快速失败的特有异常 区别3:java.util包下都是快速失败,java.util.concurrent包下都是安全失败
发表于 2016-08-27 19:11:54 回复(1)
快速失败是直接对原集合遍历的,数据修改后可能抛出异常,而安全失败是对原集合的拷贝遍历的,不会抛出异常。
发表于 2020-04-07 08:21:27 回复(0)

快速失败fail-fast

再利用迭代器遍历集合的时候,如果集合的结构发生了改变,那么就会抛出当前修改异常,因为迭代器在对集合进行遍历的时候,会使用modCount标记,如果集合的结构发生了改变,则会修改modCound的值,每次执行next和hasnext方法是会检测modCount是否为预期的值,如果这两个不相等,也就会抛出异常终止遍历。java.util包都是这种快速迭代不适合多线程的环境使用,

安全失败fail-safe

在利用迭代器进行遍历的时候,不会对原来的集合进行遍历,而是拷贝一个,这样就不会有modCount变量检测了,所以也不会抛出异常,在java.util.concurren包下都是安全失败,他们都是使用在线程下使用。缺点,在遍历的时候,有可能拿不到原集合修改之后的内容

编辑于 2020-03-31 00:01:24 回复(0)
一、快速失败机制(fail—fast)
使用快速失败机制的集合类,在使用迭代器进行遍历时,若对集合元素的内容 做了修改,则立马会抛出Concurrent Modification Exception。
实质:快速失败机制下,迭代器是直接对集合中的元素进行遍历。遍历过程中使用modCount变量来表示集合内容是否发生变化。若modCount != expectedmodCount ,则抛出异常。
场景:java.util 包下的集合类都是快速失败的,不能在多线程下并发修改。

二、安全失败机制(fail—safe
采用安全失败机制的集合容器,遍历时不是对集合内容进行直接访问,而是拷贝一份原有集合的内容,对拷贝的集合进行迭代遍历。
实质:由于是对 拷贝的集合进行迭代遍历,遍历过程中对原有集合的修改,迭代器并不会检测到,所以不会触发Concurrent Modification Exception。
优点是:多线程并发访问时,集合不会抛出Concurrent Modification Exception异常。
缺点时:迭代器访问不到 原集合修改后的内容。
场景:java.util.concurrent包下的容器都是安全失败机制(即:线程安全),可以在多线程下并发访问 和 修改。
编辑于 2019-06-21 11:16:49 回复(0)
是在遍历的过程中,集合中元素可能发生改变,所以基本上采取两种方式进行避免因为遍历过程中发生集合元素改变而触发异常,理解一个原理,真正理解了,才能用自己的话说出来,对吧,总觉得我能够和计算机这些基本的知识学习人生方法论,真的特别好,这些思想很多大神的思想,来源于生活的抽象类比到计算机中
编辑于 2018-08-30 00:12:04 回复(0)
快速失败当你在迭代一个集合时,另一个线程正在修改集合,就会跑出ConcurrentModification异常。原理就是迭代器在每次调用Next()时,就会先检验modCount是否等于expectedCount,如果不等就会抛出异常,java.util包下的所有集合类都是快速失败的。安全失败在迭代之前,先进行集合对象的拷贝然后进行迭代,因此不会抛出异常,java.util.concurrent包下的集合类都是安全失败的
发表于 2018-03-12 16:38:27 回复(0)
快速失败和安全失败是对迭代器而言的。 快速失败:当在迭代一个集合的时候,如果有另外一个线程在修改这个集合,就会抛出ConcurrentModification异常,java.util下都是快速失败。 安全失败:在迭代时候会在集合二层做一个拷贝,所以在修改集合上层元素不会影响下层。在java.util.concurrent下都是安全失败
发表于 2017-07-29 09:49:02 回复(0)
贴一个ArrayList中的Iterator的简单实现。注意modCount作用
private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        // 在创建迭代器时将当前ArrayList的修改次数赋值给 expectedModCount 保存
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            // 检查当前所在的 ArrayList 的 modCount 是否与创建 Itr 时的值一致,
            // 也就是判断获取了Itr迭代器后 ArrayList 中的元素是否被 Itr 外部的方法改变过。
            checkForComodification();
            // 具体的获取下一个元素的代码
            // ...
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            // 同 next 中的 checkForComodification 方法
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                // Itr 内部的删除元素操作,会更新 expectedModCount 值,而外部的则不会
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
}


发表于 2020-12-10 22:43:14 回复(0)
快速失败,在遍历一个集合时,对集合进行修改会抛出异常,所以不能在多线程并发修改。 安全失败,是对集合先复制一份,遍历复制的内容,所以对集合进行修改不会触发异常。所以迭代器不能访问被修改的内容。可以在多线程并发使用,并发修改。
编辑于 2020-08-31 15:05:44 回复(0)
快速失败:当你在迭代一个集合的时候,如果有另一个线程正在修改你正在访问的那个集合时,就会抛出一个ConcurrentModification异常。     在java.util包下的都是快速失败。 安全失败:你在迭代的时候会去底层集合做一个拷贝,所以你在修改上层集合的时候是不会受影响的,不会抛出ConcurrentModification异常。     在java.util.concurrent包下的全是安全失败的。
编辑于 2020-08-14 16:38:43 回复(0)

快速失败

当迭代器在遍历一个集合时,某个线程在修改集合结构(增删改),会抛出异常,java.util下的集合都是快速失败

安全失败,迭代器遍历某个集合的复制体,所以当集合被修改时是不会抛出异常的,但修改后的内容,迭代器也无法遍历到,java.util.current下的集合都是安全失败

编辑于 2019-09-16 20:51:19 回复(0)
一:快速失败(fail—fast)           在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的结构进行了修改(增加、删除),则会抛出Concurrent Modification Exception。           原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果结构发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。       注意:这里异常的抛出条件是检测到 modCount!=expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。       场景:java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)。     二:安全失败(fail—safe)       采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。       原理:由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发Concurrent Modification Exception。       缺点:基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。           场景:java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。
发表于 2019-09-11 17:01:42 回复(0)
意思就是,快速失败改动了原本结构
                  安全失败改动了拷贝文本结构
发表于 2019-08-20 09:31:44 回复(0)
快速失败:再用迭代器遍历一个集合对象时,如果遍历过程中集合对象的结构进行修改,则会抛出异常。 安全失败:采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的而是先复制原有集合内容,在拷贝的集合上进行遍历。
编辑于 2019-08-16 15:17:36 回复(0)
快速失败是指在迭代器遍历对象集合时,遍历过程中对遍历对象进行增删改会抛出异常。 安全失败不是直接在集合内容上改变而是复制一份,在复制的那一份上进行遍历
编辑于 2019-04-26 22:05:08 回复(0)