• 快速失败and安全失败


    快速失败:

    举个栗子:
     public static void main(String[] args) {
            ArrayList<String> list=new ArrayList<>();
            list.add("包龙星");
            list.add("常威");
            list.add("来福");
            list.add("豹子头");
            list.add(null);
            Iterator<String> iterator=list.iterator();
            while (iterator.hasNext()){
                String s=iterator.next();
                    if(s.equals("常威"));
                    list.remove("常威");
            }
        }
    运行结果:
    Exception in thread "main" java.util.ConcurrentModificationException
        at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
        at java.util.ArrayList$Itr.next(ArrayList.java:859)
        at com.Collection.ArrayListTest.main(ArrayListTest.java:23)

       jdk上异常解释:某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection。通常在这些情况下,迭代的结果是不确定的。如果检测到这种行为,一些迭代器实现(包括 JRE 提供的所有通用 collection 实现)可能选择抛出此异常。执行该操作的迭代器称为快速失败 迭代器,因为迭代器很快就完全失败,而不会冒着在将来某个时间任意发生不确定行为的风险。  

    也就是说当我们通过迭代器遍历集合时,如果直接通过集合增删了集合中的元素,就会抛出ConcurrentModificationException,称为快速失败!

    源码分析:(注意重点红色标记)

    Iterator部分源码:

       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;
    
            Itr() {}
    
            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];
            }

    checkForComdification方法

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

    Arraylist的删除源码: 

    private void fastRemove(int index) {
            modCount++;
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
                                 numMoved);
            elementData[--size] = null; // clear to let GC do its work
        }

            原理分析:迭代器第一次被调用时,会将一个modCount的值保存在expectedmodCount中,每当迭代器.next()操作遍历下一个元素之时,都会检查modCount变量是否为expectedmodCount值,集合在被遍历期间如果直接通过集合的方法改变集合内容,modCount++,进而导致下次进入.next()方法时匹配失败,抛出异常

           ps:java.util包下面的所有的集合类都是快速失败的

    安全失败:

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

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

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

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

     
  • 相关阅读:
    thinkphp5自定义sql排序
    php版雪花算法生产唯一ID 分库分表专用
    java和php保持一致的md5加密
    rabbitmq新版本使用
    pentaho-kettle+eclipse 搭建本地源码
    《我们好像在哪见过》
    《邂逅》-----徐志摩
    Oracle数据库查询和取出表中重复记录
    Kettle提取数据,数据库中文字符乱码问题
    kettle报错收集- java.sql.SQLException: Streaming result set com.mysql.jdbc.RowDataDynamic@160750a6 is still active
  • 原文地址:https://www.cnblogs.com/jiezai/p/11134582.html
Copyright © 2020-2023  润新知