Java 中的 Fail-Fast 与 Fail-Safe

Fail-Fast与Fail-Safe:深入理解Java中的这两种机制 Fail-Fast指的是一种设计哲学,即当系统检测到一个不一致或错误时,立即失败(抛出异常),而不是继续执行可能产生不确定结果的操作。这种机制的目的是尽快地发现错误,避免潜在的更严重的问题。Fail-Safe是另一种设计机制,它确保系统在发生故障时仍然能够安全地运行,不会崩溃或产生不可预测的行为。Fail-Safe机制通常通过创建数据的副本或使用锁机制来实现,以确保在操作过程中数据的一致性和完整性。Fail-Fast和Fail-Safe是Java编程中两种重要的机制,它们分别适用于不同的场景。 阅读详情

Fail-Fast 与 Fail-Safe 机制

相信不少同学都遇到过在遍历集合的同时,判断满足某些条件的时候 remove 元素,然后报错的情况,这其实是 Java 中集合的 Fail-Fast 机制在起作用,下面来看下什么是 Fail-Fast 机制~

Fail-Fast

是 Java 集合的一种错误检测机制。当遍历集合的同时修改集合或多线程对集合进行结构上的改变操作时,有可能会产生 fail-fast 机制,会抛出 ConcurrentModificationException 异常。

集合(如,常用的 ArrayList)的迭代器在调用 next()、remove() 方法时,都会调用 checkForComodification 方法检测 modCount == expectedModCount 是否成立,若不成立,则抛出 ConcurrentModificationException 异常,也就是 fail-fast 机制。modCount 是每次改变集合数量时,都会改变的值。

ArrayList 的内部类 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; // 初始化 expectedModCount 为 modCount 的值
    public E next() {
            checkForComodification();
            ...
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            ...
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                // 修正 expectedModCount 值
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

可以看到迭代器在每次调用 next()、remove() 方法前,都会调用 checkForComodification() 方法检查 modCount 和 expectedModCount 的值是否相等,不相等则抛出 ConcurrentModificationException 异常。expectedModCount 的值默认初始化为 modCount 的值,且只有在调用 Itr 自己的 remove() 方法时,才会修正 expectedModCount 的值。即:

不要在 foreach 循环(增强 for 循环编译后的源码就是使用了迭代器)里调用 ArrayList 自己的 remove/add 操作。请统一使用迭代器 Iterator 方式遍历 + remove 操作,如果是并发操作,需要对 Iterator 对象加锁。

看下面几个例子

如下代码会抛出异常吗?
Q1
List<String> list = Arrays.asList("1", "2", "3", "4");
for (String i : list) {
    if ("1".equals(i)) {
        list.remove("1");
    }
}

不会抛出 ConcurrentModificationException,但是会抛出 UnsupportedOperationException 异常。

Arrays.asList 中生成的 ArrayList 是 Arrays 中的内部类,其中的数组用 final 修饰,不支持增删改,只可以调用 get 和 set 方法。

Q2
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String tmp = iter.next();
    System.out.println(tmp);
    if (tmp.equals("3")) {
        list.remove("3");
    }
}

不会。remove 倒数第二个元素(3)之后,cursor 会变为 3,同时数组 size 会减一。迭代器中的 hasNext() 方法会判断当前 cursor(下一个要返回的下标,会在 remove 方法中置为 lastRet,即上一个返回过的元素的下标)与 size 相等,不会进入循环。也就是最后一个元素 “4”,不会访问到。

// ArrayList.Itr
...
int cursor;       // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
public E next() {
	if (modCount != expectedModCount)
		throw new ConcurrentModificationException();
	int i = cursor;
	if (i >= limit)
		throw new NoSuchElementException();
	Object[] elementData = ArrayList.this.elementData;
	if (i >= elementData.length)
		throw new ConcurrentModificationException();
	cursor = i + 1;
	return (E) elementData[lastRet = i];
}
public void remove() {
	...
	ArrayList.this.remove(lastRet);
	cursor = lastRet; // cursor 赋值为 lastRet
	lastRet = -1;
	expectedModCount = modCount;
	limit--;
	...
}
public boolean hasNext() {
    return cursor != size;
}
...
Q3
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String tmp = iter.next();
    System.out.println(tmp);
    if (tmp.equals("4")) {
        list.remove("4");
    }
}

会,问题与上面的有些相似,删除最后一个元素后,数组 size 变成 3,cursor 是 4,hasNext() 判断不相等,会再次进入循环,则抛出异常。

public E next() {
	...
	if (i >= limit)
		throw new NoSuchElementException();
	...
}
如何避免 fail-fast 异常
  1. 如果要在遍历时修改集合,使用迭代器的 remove 方法,迭代器的 remove 方法会修正其内部的 expectedModCount 值。
  2. 并发环境,需要对 Iterator 对象加锁
  3. 使用 Collections.synchronizedList
  4. 使用 CopyOnWriteArrayList(采用 fail-safe 机制)

Fail-Safe

Fail-Safe 机制与 Fail-Fast 机制相反,为了避免 Fail-Fast 机制抛出异常,在迭代器的实现上去掉了 modCount 的 ConcurrentModificationException 检查机制。避免了 Fail-Fast。

使用 Fail-Safe 机制的容器 - CopyOnWriteArrayList

参考文章

Fail-fast、Fail-safe 机制

java集合中的fail-fast与fail-safe两种模式 线程不安全的集合在获取迭代器迭代的时候,如果集合中的元素发生了变化,例如新增或者删除,由于线程不安全,迭代器在next时会直接抛出concurrentModificationException,通过内部的一个modCount判断是否等于expectedModCount来进行比较。可以看到j.u.c包下的线程安全的集合在迭代的过程中,如果集合的元素发生了修改,并不会抛异常,这就是fail-safe机制,但是缺点就是元素的修改并不会立刻反映出来,适用于读多写少的场景。fail-safe案例。 阅读详情

相关推荐

Java集合中的 Fail-Fast 与 Fail-Safe 机制全面分析

在 Java 中,集合类的遍历操作在多线程环境下可能会遇到并发修改的问题。fail-fast和fail-safe。它们各自的实现和应用场景有所不同。在本文中,我们将全面分析这两种机制,并通过具体示例,讲解异常机制、和的使用以及遍历过程中集合修改的安全策略。Java 集合中的 fail-fast 和 fail-safe 机制为开发者提供了不同的并发控制方式。通过了解和使用这些机制,可以更有效地处理多线程环境中的集合遍历和修改操作。通过。

喵手的博客 993

Java集合中fail-fast和fail-safe机制详解

在使用集合时候,大家应该都遇到过或听过并发修改异常(ConcurrentModificationException),这其实是Java集合中的一种fail-fast机制,为了避免触发fail-fast机制,Java中还提供了一些采用fail-safe机制的集合类,本篇文章就系统的介绍一下这两种机制。

让~学习~成为一种习惯(橡 皮 人の技术博客) 1835

机器视觉避坑指南:为什么你的Halcon划痕检测总漏检?(附优化方案)

本文深入剖析了Halcon在表面划痕检测中漏检率高的常见原因,如灰度值波动、噪声干扰及形态学参数设置不当。针对复杂背景与低对比度划痕,提出了超越官方例程的多尺度纹理分析与特征融合优化方案,旨在帮助开发者构建更鲁棒、稳定的机器视觉检测流程,有效提升检出率。

weixin_29057163的博客 234

Java提高篇(三四)-----fail-fast机制

在JDK的Collection中我们时常会看到类似于这样的话:        例如,ArrayList:注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅

chenssy 的技术博客 6万+

QT的温湿度显示系统

大家好,这里是石侃侃的博客,欢迎前来讨论这篇文章介绍的是DHT11在2440上的基于Qt5.6的应用基于单片机系统的温湿度监测系统构成框图如图2-1所示。图2-1 系统构成框图该系统采用单片机s3c2440作为了本设计的核心元件。利用LCD作为了显示器件,利用触摸屏作为用户界面输入设备,第一行显示当前实时的温度,湿度,第二行依次显示历史时刻最高的温度值,最高的湿度值。第三行是一个文本框,记录了程...

zxpcus的博客 1万+

团结引擎+OpenHarmony 2实战篇:从零构建鸿蒙应用开发环境

本文详细介绍了如何从零开始构建鸿蒙应用开发环境,重点讲解了团结引擎与OpenHarmony 2的实战配置步骤。内容包括DevEco Studio安装、OpenHarmony SDK配置、团结引擎集成及项目创建等关键环节,帮助开发者快速搭建高效的开发环境,提升鸿蒙应用开发效率。

weixin_29294395的博客 265

Java中Fail - Fast与Fail - Safe机制

在 Java 集合框架中,Fail - Fast(快速失败)和 Fail - Safe(安全失败)是两种不同的迭代机制,用于处理集合在迭代过程中被修改的情况。

dsq_MaDing的博客 1156

如何使用 Ansys OptiSlang 同时运行多个参数化设计研究

了解如何通过使用 OptiSLang 同时运行多个参数化设计研究来提高工作效率。

jkh920184196的博客 2387

网易Java面试被问:fail-safe和fail-fast

Java集合框架中的Fail-Fast与Fail-Safe机制对比分析。Fail-Fast(如ArrayList)通过modCount机制在并发修改时立即抛出异常,保证数据一致性但牺牲并发性;Fail-Safe(如CopyOnWriteArrayList)通过数据副本实现安全遍历,允许并发修改但存在内存开销和弱一致性。选型时应考虑读写比例和并发需求:单线程或完全同步场景适合Fail-Fast,读多写少的高并发场景适合Fail-Safe。两种机制体现了不同的设计哲学,开发调试阶段推荐Fail-Fast快速暴露

xh2277659985的博客 1267

时序分析-由D触发器结构来理解Tsu、Th

FPGA逻辑单元内的D触发器(D-FF)是一种在时钟的上升沿(或下降沿)将输入信号的变化传送至输出的边沿触发器。 数字电子技术基础-闫石(第五版)边沿D触发器内部结构见下图: 而FPGA原理与结构(日)一书中,内部结构较之上图多了俩反相器: 由传输门和俩个反相器组成一个循环电路(锁存器),再由前后两级锁存器按主从结构链接而成。这里的传输门起开关作用,随着CLK的状态变化切换开关。只看输出的话,前级锁存器的值会随着时钟输入的变化井然有序地传入后级锁存器。为了防止时钟信号变化时输入信号发生冒险,从而使稳定.

XY_Chang的博客 3974

手把手教您同花顺如何设置大盘分时均价线

本文将手把手教你如何在同花顺PC端开启大盘指数分时图📈

XiaoqiangClub的博客 4417

谈谈Java集合中的fail-fast和fail-safe

摘要:Java集合框架中,迭代器处理集合修改有两种策略:fail-fast快速失败和fail-safe安全失败。fail-fast通过modCount变量检测结构性修改,发现不一致即抛出ConcurrentModificationException,如ArrayList等非线程安全集合。fail-safe则通过遍历集合副本来避免异常,如ConcurrentHashMap等并发集合,但无法获取最新修改。前者注重异常检测,后者保证遍历安全但牺牲实时性。

qq_58284486的博客 659

Java与OSG的梦幻联动:深入编译OpenSceneGraph的Java JNI桥梁,开启3D视觉盛宴的奇幻之旅

🔥关注墨瑾轩,带你探索编程的奥秘!🚀🔥超萌技术攻略,轻松晋级编程高手🚀🔥技术宝库已备好,就等你来挖掘🚀🔥订阅墨瑾轩,智趣学习不孤单🚀🔥即刻启航,编程之旅更有趣🚀在编译OpenSceneGraph (OSG) 的Java版本时,首先需要了解OSG本身是一个主要用于3D图形和视觉仿真的开源库,它主要支持C++。然而,OSG 也支持通过JNI(Java Native Interface)与Java集成,这允许Java程序调用OSG的C++库。

java专栏 870

Java中的fail-fast和fast-safe机制

文章目录1. 引入2. fail-fast3. fail-safe 1. 引入 不管是在ArrayList、Hashtable还是HashMap的源码中,我们在属性字段都可以看见modCount字段的存在。它用来表示集合修改的次数,例如当执行put操作时就会将modCount加1,都是在其他常用的方法中并没有看到它的具体使用。而它却是fail-fast和fast-safe机制的一种重要参考值,下面就了解一下这两种机制,以及modCount在其中所起到的作用。 并发修改:当一个或多个线程正在遍历一个集合C

Forlogenの解忧杂货铺 1381

基于泰勒展开改进的物理信息神经网络

基于泰勒展开改进的物理信息神经网络

天天酷科研的博客 504

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Java 集合迭代中的 fail-fast 与 fail-safe 机制详解

fail-fast 和 fail-safe 是 Java 集合框架中两种不同的迭代机制,适用于不同的场景。理解它们的工作原理和适用场景,能够帮助我们更好地选择合适的集合类型,避免潜在的并发问题。fail-fast适用于单线程场景,或需要强一致性的场景。通过迭代器的remove()方法进行修改,确保数据一致性。fail-safe适用于多线程场景,或需要高并发写操作的场景。注意内存开销和数据一致性问题。

2501_92441786的博客 950

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Java 集合中的 fail-fast 与 fail-safe 机制详解

摘要: Java集合中的fail-fast(快速失败)和fail-safe(安全失败)是两种应对迭代时集合修改的机制。fail-fast通过modCount校验检测修改并立即抛出异常,适用于单线程环境,保证数据一致性但非线程安全。fail-safe基于写时复制策略,迭代器操作快照不抛异常,适合多线程读多写少场景,但存在数据延迟和内存开销。关键区别在于异常处理、线程安全性和数据一致性,选择需根据环境需求:fail-fast适合单线程实时操作,fail-safe适合并发安全场景。

qq_29515513的博客 412

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

JAVA集合类中的fail-fast与fail-safe机制

之所以会抛出CMException异常,是因为我们的代码中使用了增强for循环,而在增强for循环中,集合遍历是通过iterator进行的,但是元素的add/remove却是直接使用的集合类自己的方法。这就导致iterator在遍历的时候,会发现有一个元素在自己不知不觉的情况下就被删除/添加了,就会抛出一个异常,用来提示用户,可能发生了并发修改!

weixin_44300435的博客 151

Java中的Fail-Fast和Fail-Safe机制是什么?

Fail-Fast:快速发现并发修改问题,适用于单线程环境。实现简单,性能较高,但在多线程环境下可能抛出异常。Fail-Safe:避免因并发修改导致异常,适用于多线程环境。实现复杂,性能较低,但更适合高并发场景。根据具体的使用场景选择合适的机制,可以有效提高程序的健壮性和性能。一句话:Fail-Fast的目的是为了快速抛出错误让程序感知,而Fail-Safe的目的是程序进行容灾,避免因为异常导致程序停止。

weixin_45762066的博客 735

java 中的fail-fast和fail-safe机制

一、fail-fast 快速失败机制 在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加、删除、修改),则会抛出Concurrent Modification Exception。 原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个 modCount 变量。集合在被遍历期间如果内容发生变化,就会改变modCoun...

西木风落 344

Java集合类源码中的modCount属性有什么用?fail-fast和fai-safe

一.modCount字段解释 在看HashMap,HashTable,PriorityQueue等集合类源码时,经常会发现在add,remove方法的代码块中,都有一个modCount++字段,它表示什么呢 transient int modCount; 注释如下 /** * The number of times this HashMap has been structurally...

atomatom98的博客 413

fail safe java_fail-fast与fail-safe在Java集合中的应用

fail-fast与fail-safe简介如果一个系统,当有异常或者错误发生时就立即中断执行,这种设计称之为fail-fast。相反如果我们的系统可以在某种异常或者错误发生时继续执行,不会被中断,这种设计称之为fail-safe。fail-fast与fail-safe在Java迭代器中的设计在Java中,最典型的fail-fast与fail-safe就是关于迭代器的设计。通常情况下,那些线程不安全...

weixin_33416318的博客 291

fail-fast与fail-safe在Java集合中的应用

fail-fast与fail-safe简介 如果一个系统,当有异常或者错误发生时就立即中断执行,这种设计称之为fail-fast。相反如果我们的系统可以在某种异常或者错误发生时继续执行,不会被中断,这种设计称之为fail-safe。 fail-fast与fail-safe在Java迭代器中的设计 在Java中,最典型的fail-fast与fail-safe就是关于迭代器的设计。通常情况下,那些线程...

JAVA那些事 187

【Java面试高频-集合】Java集合中的快速失败机制fail-fast和fail-safe是怎么样的?

Java集合的快速失败机制fail-fast和fail-safe? fail-fast机制 在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了(增加、删除),会抛出Concrrent Modification Eception。 原理:迭代器在遍历过程中直接访问集合中的元素,并且在遍历过程中使用一个modCount变量。集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hasNext/next遍历下一个元素时,都会检测modCount是否为expectedmodC

Mind_programmonkey的博客 391

通过4个问题简单讲解:Java 集合中的 fail-fast 和 fail-safe 是什么?

fail-fast(快速失败):是“严父”。它在单线程或低并发下,用异常来教育程序员,“别乱动正在遍历的东西!,保证代码逻辑的绝对严谨。fail-safe(安全失败):是“慈母”。它在高并发下,宁可给你看旧数据(快照),也不让系统崩溃,“天塌下来也要先把响应返回给用户”,保证服务的高可用。在Java中,ArrayList和都不是用链表实现的,它们内部维护的就是一个普通的 JavaObject[]数组。你可以把它想象成一个“装对象的连续格子”。// 在 ArrayList 中// 这就是底层数组。

HDZW_ZQBX___的博客 390
上一篇: Android 面试系列(三)Java 集合类源码要点
逆袭的L
博客等级 码龄12年 6粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值