fail-fast 与 fail-safe

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

fail-fast:当再遍历集合(以非线程安全的HashMap为例)的时候,若是监测到modCount值发变化,则直接抛出ConcurrentModificationException的异常,若是是使用迭代器遍历时修改,会在第一次的时候将异常抛出,若是是用forEach循环的话,则会在执行完全部的代码后再抛出异常(之前的for(Object object : list)的语法方式,通过编译以后变成迭代器iterator,但java8的foreach编译以后并不会变成迭代器iterator,而是编译后的结果与编写时几乎同样,因此java8的foreach可能不是纯粹是语法糖)安全

HashMap<Integer, Integer> hashMap = new HashMap();
        hashMap.put(1, 1);
        hashMap.put(2, 2);
        hashMap.put(3, 3);

        // 测试一,当执行第一个的时候就会报错,不会执行下一个
        Set set = hashMap.entrySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
            hashMap.put(10, 10);
            System.out.println("此时 hashMap 长度为" + hashMap.size());
        }
        // 测试一结果:
//        1=1
//        此时 hashMap 长度为4
//        java.util.ConcurrentModificationException

        // 测试二,用原始的for循环进行遍历,测试结果同测试一,缘由其实时for是语法糖,编译后就会变化迭代器
        Set<Integer> keySet = hashMap.keySet();
        for (Integer index : keySet) {
            System.out.println(hashMap.get(index));
            hashMap.put(10, 10);
            System.out.println("此时 hashMap 长度为" + hashMap.size());
        }

        // 测试三,会执行完for的全部代码,最后再抛出异常,java8的循环已经不一样于迭代器
        hashMap.forEach((o, o2) -> {
            System.out.println(String.valueOf(o) + String.valueOf(o2));
            hashMap.put(4, 4);
            System.out.println("此时 hashMap 长度为" + hashMap.size());
        });

        // 测试三结果:
//        11
//        此时 hashMap 长度为4
//        22
//        此时 hashMap 长度为4
//        33
//        此时 hashMap 长度为4
//        44
//        此时 hashMap 长度为4
//        java.util.ConcurrentModificationException

fail-safe(针对线程安全的集合,例如:ConcurrentHashMap)测试

网上解释:当在作遍历的时候,集合会复制出一份,再作遍历,这样即便原集合作了修改,也不会影响当前遍历,即遍历有三个元素的集合,在遍历期间,添加了一个元素,在遍历过程当中,添加后的元素不会被遍历到线程

但我测试以后好像不是这样的,可能时jdk版本的问题吧,个人jdk版本时1.8.0_152code

ConcurrentHashMap<Integer, Integer> hashMap = new ConcurrentHashMap<>();
        hashMap.put(1, 1);
        hashMap.put(2, 2);
        hashMap.put(3, 3);

        // 测试一,在遍历期间会将添加的元素加进去,但不会抛异常,与网上的说法有些不一致,网上说法时不会理会遍历期间添加的元素
        Set set = hashMap.entrySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
            hashMap.put(10, 10);
            System.out.println("此时 hashMap 长度为" + hashMap.size());
        }
        // 测试一结果:
//        1=1
//        此时 hashMap 长度为4
//        2=2
//        此时 hashMap 长度为4
//        3=3
//        此时 hashMap 长度为4
//        10=10
//        此时 hashMap 长度为4

        // 测试二, 结果同一
        Set<Integer> keySet = hashMap.keySet();
        for (Integer index : keySet) {
            System.out.println(hashMap.get(index));
            hashMap.put(10, 10);
            System.out.println("此时 hashMap 长度为" + hashMap.size());
        }

        // 测试三,
        hashMap.forEach((o, o2) -> {
            System.out.println(String.valueOf(o) + String.valueOf(o2));
            hashMap.put(4, 4);
            System.out.println("此时 hashMap 长度为" + hashMap.size());
        });

        // 测试三结果:
//        11
//        此时 hashMap 长度为4
//        22
//        此时 hashMap 长度为4
//        33
//        此时 hashMap 长度为4
//        44
//        此时 hashMap 长度为4
相关文章
相关标签/搜索