Fail-Fast快速失败机制

Fail-Fast快速失败机制

1.简介

  1. fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。
  2. 要了解fail-fast机制,我们首先要对ConcurrentModificationException 异常有所了解。当方法检测到对象的并发修改,但不允许这种修改时就抛出该异常。同时需要注意的是,该异常不会始终指出对象已经由不同线程并发修改,如果单线程违反了规则,同样也有可能会抛出改异常。
  3. 诚然,迭代器的快速失败行为无法得到保证,它不能保证一定会出现该错误,但是快速失败操作会尽最大努力抛出ConcurrentModificationException异常,所以因此,为提高此类操作的正确性而编写一个依赖于此异常的程序是错误的做法,正确做法是:ConcurrentModificationException 应该仅用于检测 bug

JavaDoc:

protected transient int modCount = 0
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 iterator and listIterator methods ,If the value of this field changes unexpectedly, the iterator (or list iterator) will throw a ConcurrentModificationException in response to the next, remove, previous, set or 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 add(int, E) and remove(int) methods (and any other methods that it overrides that result in structural modifications to the list). A single call to add(int, E) or remove(int) must add no more than one to this field, or the iterators (and list iterators) will throw bogus ConcurrentModificationExceptions. If an implementation does not wish to provide fail-fast iterators, this field may be ignored.

    protected transient int modCount = 0;

示例:

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("name");
        list.add("age");
        list.add("grade");

        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            if ( iterator.next().equals("name")) {
                list.remove("name");//  **** remove倒数第二个元素时候不会报错 success
            }
        }
    }

Exception in thread “main” java.util.ConcurrentModificationException
at java.util.ArrayList I t r . c h e c k F o r C o m o d i f i c a t i o n ( A r r a y L i s t . j a v a : 901 ) a t j a v a . u t i l . A r r a y L i s t Itr.next(ArrayList.java:851)
at Test.main(Test.java:15)

==remove倒数第二个元素时候不会报错==

源码分析:

   public Iterator<E> iterator() {
        return new Itr();
    }

    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount; //获取Iterator遍历集合时把集合的结构变动次数传入

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

        @SuppressWarnings("unchecked")
        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+1
                throw new ConcurrentModificationException();
        }
    }

==分析移除倒数第二个元素时==:

   public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("name");
        list.add("age");
        list.add("grade");

        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            if ( iterator.next().equals("age")) {
                list.remove("age");
            }
        }
    }

由上面代码可以看出当List用iterator遍历到倒数第二个元素时(已调用next方法),cursor=2,用remove方法删除会使得size()减1变为2,于是当iter调用hasNext方法时,cursor==size(),返回false,结束遍历,无异常。

猜你喜欢

转载自blog.csdn.net/RamboKitty/article/details/80547857
今日推荐