• fail-fast 和 fail-safe 快速学习


    首选说一下这两个的概念

    fail-fast(快速失败)

    概念

    fail-fast(快速失败)是Java对java.util包下的所有集合类的是一种错误检测机制;

    划重点!是一种错误检查机制,那么下面咱们再来看看是怎样的机制:

    快速失败机制:在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加、删除、修改),则会抛出Concurrent Modification Exception。

    原理

    原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。

    注意:这里异常的抛出条件是检测到 modCount!=expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。

    应用场景

    刚才j也说到 ava.util包下的集合类都是快速失败的

    所以场景就是:不能在多线程下发生并发修改(迭代过程中被修改)。

    fail-safe(安全失败)

    概念

    fail-safe(安全失败)是Java对 java.util.concurrent 包下的所有集合类的是一种错误检测机制;

    首先,安全失败也是一种错误检查机制,那么下面咱们再来看看是怎样的机制:

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

    原理

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

    应用场景

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

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

    二者区别

    快速失败安全失败
    java.util包下面的所有的集合类都是快速失败的而java.util.concurrent包下面的所有的类都是安全失败的
    异常fail-fast(快速失败)的迭代器会抛出ConcurrentModificationException异常安全失败是基于对底层集合做拷贝,所以,它不受源集合上修改的影响,安全失败的迭代器永远不会抛出这样的异常。

    代码示例

    完整代码如下所示,下面我们通过断点模拟多线程修改集合的操作

    package com.mian.array;
    
    import java.util.ArrayList;
    import java.util.concurrent.CopyOnWriteArrayList;
    
    public class FailFastVsFailSafe {
        // fail-fast 一旦发现遍历的同时其它人来修改,则立刻抛异常
        // fail-safe 发现遍历的同时其它人来修改,应当能有应对策略,例如牺牲一致性来让整个遍历运行完成
    
        private static void failFast() {
            ArrayList<Student> list = new ArrayList<>();
            list.add(new Student("A"));
            list.add(new Student("B"));
            list.add(new Student("C"));
            list.add(new Student("D"));
            for (Student student : list) {
                System.out.println(student);
            }
            System.out.println(list);
        }
    
        private static void failSafe() {
            CopyOnWriteArrayList<Student> list = new CopyOnWriteArrayList<>();
            list.add(new Student("A"));
            list.add(new Student("B"));
            list.add(new Student("C"));
            list.add(new Student("D"));
            for (Student student : list) {
                System.out.println(student);
            }
            System.out.println(list);
        }
    
        static class Student {
            String name;
    
            public Student(String name) {
                this.name = name;
            }
    
            @Override
            public String toString() {
                return "Student{" +
                        "name='" + name + '\'' +
                        '}';
            }
        }
    
        public static void main(String[] args) {
            failFast();
    //        failSafe();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    调试fail-fast

    在打印C这打一个断点:

    student.name.equals("C")
    
    • 1

    在这里插入图片描述

    注释safe
    在这里插入图片描述
    debug运行

    添加计算表达式,加一个元素E
    在这里插入图片描述

    list.add(new Student("E"))
    
    • 1

    在这里插入图片描述
    让他继续运行:
    在这里插入图片描述
    控制台抛出异常:
    在这里插入图片描述

    Exception in thread "main" java.util.ConcurrentModificationException
    	at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    	at java.util.ArrayList$Itr.next(ArrayList.java:851)
    	at com.mian.array.FailFastVsFailSafe.failFast(FailFastVsFailSafe.java:16)
    	at com.mian.array.FailFastVsFailSafe.main(FailFastVsFailSafe.java:50)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    调试fail-safe

    注释failFast,取消注释failSafe

    在这里插入图片描述

    设置断点过程与上面一样:
    在这里插入图片描述
    调试过程与上面一样不再贴图了

    循环的时候打印的是原集合,并且没有报错
    在这里插入图片描述

  • 相关阅读:
    idea创建springboot项+集成阿里连接池druid
    华为机试真题 Java 实现【学生方阵】
    氨基酸代谢:从基础到应用,揭示其在健康与疾病的角色
    生产问题分析:批量执行慢,根据日志进行分析。
    动态创建类- ByteBuddy
    用Python订正数据
    【数据结构与算法】之深入解析“网格游戏”的求解思路和算法示例
    从“AI玩具”到“创作工具”的云原生改造之路
    Python之办公自动化SFTP
    SpringBoot面试之SpringBoot自动装配原理
  • 原文地址:https://blog.csdn.net/weixin_45525272/article/details/126207674