Java中快速失败和安全失败

一、快速失败和安全失败的环境

         快速失败的环境:java.util包下的容器类都是快速失败的,不能在多线程下对集合进行修改,如果进行修改,则抛出ConcurrentModificationException异常。

        安全失败的环境java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改,则不会抛出ConcurrentModificationException异常。

二、快速失败fail-fast):

        在使用迭代方式对集合进行遍历的时候,如果出现A线程对集合进行遍历,而同时又有一个B线程对该集合进行一些(增加、删除、修改)等操作时,此时A线程得到的是脏数据(该集合中的元素已经被修改),这个时候,A线程就会抛出ConcurrentModificationException异常,这就是快速失败。

原理:迭代器在遍历集合中的元素时,第一次进去就会产生一个modCount、和expectedmodCount的变量,

       modCount:用来存储对集合的修改次数,创建时默认为1次(只要是修改(添加,删除)了该集合的内容或者遍历(查询)了该集合的内容,modCount的次数都会进行+1)

      expectedmodCount:仅表示迭代器对集合进行查询的次数(每查询一次,expectedmodCount都会+1)

查看ArrayList集合源代码的next()方法,源代码如下

        @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];
        }

在next()方法中,可以看到在该方法中执行了checkForComodification()方法 

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

我们发现,在checkForComodification()方法中进行了一个modCount和expectedmodCount值的判断,如果modCount!=expectedmodCount,那么也就是在A线程还在进行迭代的过程中,有其他线程对该集合进行修改,这时,A程序就抛出了ConcurrentModificationException异常。

三、安全失败(fail-safe

          采用安全失败机制的集合容器,在遍历集合时不是直接访问原来的集合,而是先复制原有集合内容,拷贝一份,然后在复制后的集合上进行遍历(每次访问,都会复制,包括修改,删除)

        原理:由于迭代时是对原集合的复印件进行遍历的,所以在遍历过程中对原集合所作的修改操作并不能被迭代器检测到(虽然是脏数据,但还是不会抛出异常),所以不会触发ConcurrentModificationException异常,例如CopyOnWriteArrayList集合。

      若有不正之处请多多谅解,并欢迎批评指正

猜你喜欢

转载自blog.csdn.net/weixin_42611208/article/details/84548308