fail-fast快速失败机制和fail-safe安全失败机制

**

fail-fast快速失败机制定义

**
java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。
**

fail-fast快速失败机制产生情况

**
1.单线程情况下,使用迭代器遍历对象时候,修改了集合的结构(添加、删除、修改元素)

      ArrayList<Integer> integers=new ArrayList<Integer>();
        integers.add(2);
        integers.add(1);
        integers.add(null);

        Iterator iterator=integers.iterator();
        while (iterator.hasNext()){
            Integer value= (Integer) iterator.next();
            if (value.equals(2)){
                integers.remove(value);
            }
            //integers.add(1);
    

        }

fail-fast快速失败机制和fail-safe安全失败机制_第1张图片
2.在多线程环境下,如果对集合对象进行并发修改,那么就会抛出ConcurrentModificationException异常。

fail-fast快速失败机制原因

以ArrayList为例,查看ArrayList和Iterator源码
ArrayList的父类AbstractList中定义了一个modCount

    /**
     * The number of times this list has been structurally modified.
     * Structural modifications are those that change the size of the
     * list, or otherwise perturb it in such a fashion that iterations in
     * progress may yield incorrect results.
     *
     * 

This field is used by the iterator and list iterator implementation * returned by the {@code iterator} and {@code listIterator} methods. * If the value of this field changes unexpectedly, the iterator (or list * iterator) will throw a {@code ConcurrentModificationException} in * response to the {@code next}, {@code remove}, {@code previous}, * {@code set} or {@code add} operations. This provides * fail-fast behavior, rather than non-deterministic behavior in * the face of concurrent modification during iteration. * *

Use of this field by subclasses is optional. If a subclass * wishes to provide fail-fast iterators (and list iterators), then it * merely has to increment this field in its {@code add(int, E)} and * {@code remove(int)} methods (and any other methods that it overrides * that result in structural modifications to the list). A single call to * {@code add(int, E)} or {@code remove(int)} must add no more than * one to this field, or the iterators (and list iterators) will throw * bogus {@code ConcurrentModificationExceptions}. If an implementation * does not wish to provide fail-fast iterators, this field may be * ignored. */ protected transient int modCount = 0;//记录list修改次数

ArrayList迭代器定义了一个expectedModCount=modCount
fail-fast快速失败机制和fail-safe安全失败机制_第2张图片
当使用迭代器访问集合对象时候,如果修改了集合结构就会使得modCount+1,使得expectedModCount!==modCount,从而报ConcurrentModificationException异常
fail-fast快速失败机制和fail-safe安全失败机制_第3张图片

fail-fast快速失败机制和fail-safe安全失败机制_第4张图片
注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。

fail-fast快速失败机制解决方法

1.在使用modCount的方法中都加上synchronized关键字,但是不推荐因为增删造成的同步锁可能会阻塞遍历操作
2.用CopyOnWriteArrayList来替换ArrayList。推荐使用该方案
CopyOnWriteArrayList,与ArrayList的区别在于CopyOnWriteArrayList所有可变操作对原数组进行了一次新的复制来实现,因此是线程安全的,而且CopyOnWriteArrayList在迭代器中修改结构不会报ConcurrentModificationException异常,但是该类产生的开销比较大(数组复制)。但是两种情况下非常适用。
1.在不能或不想进行同步遍历,但又需要从并发线程中排除冲突时。2.当遍历操作的数量大大超过可变操作的数量时。

  Iterator<Integer> iterator2=copyOnWriteArrayList.iterator();
        while (iterator2.hasNext()){
            int value=iterator2.next();
            copyOnWriteArrayList.add(1);
        }

fail-safe安全失败机制定义

fail-safe任何对集合结构的修改都会在一个复制的集合上进行修改,因此不会抛出ConcurrentModificationException,上面的CopyOnWriteArrayList就是fail-safe机制,以及ConcurrentHashMap也是fail-safe机制
fail-safe的优点就是不会报ConcurrentModificationException异常
缺点是(1)需要复制集合,产生大量的无效对象,开销大
(2)无法保证读取的数据是目前原始数据结构中的数据。

你可能感兴趣的:(Java,Java基础)