Java集合框架剖析(5)----fail-fast机制

什么是 fail-fast机制 看着一篇就够了 fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。在详细介绍fail-fast机制的原理之前,先通过一个示例来认识fail-fast。CopyOnWrite容器即写时复制的容器。 阅读详情

在JDK的Collection中我们时常会看到类似于这样的话:

例如,ArrayList:

注意,迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败迭代器会尽最大努力抛出 ConcurrentModificationException。因此,为提高这类迭代器的正确性而编写一个依赖于此异常的程序是错误的做法:迭代器的快速失败行为应该仅用于检测 bug。
这里写图片描述
HashMap中:

注意,迭代器的快速失败行为不能得到保证,一般来说,存在非同步的并发修改时,不可能作出任何坚决的保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException。因此,编写依赖于此异常的程序的做法是错误的,正确做法是:迭代器的快速失败行为应该仅用于检测程序错误。

在这两段话中反复地提到”快速失败”。那么何为”快速失败”机制呢?

“快速失败”也就是fail-fast,它是Java集合的一种错误检测机制。当多个线程对集合进行结构上的改变的操作时,有可能会产生fail-fast机制。记住是有可能,而不是一定。例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,而不是简单的修改集合元素的内容),那么这个时候程序就会抛出 ConcurrentModificationException 异常,从而产生fail-fast机制。

所以第一点在并发的情况下使用ArrayList,HashMap不是完全安全的。

示例代码

这里写图片描述
运行结果
这里写图片描述

原因分析

fail-fast产生的原因就在于程序在对 collection 进行迭代时,某个线程对该 collection 在结构上对其做了修改,这时迭代器就会抛出 ConcurrentModificationException 异常信息,从而产生 fail-fast。

要了解fail-fast机制,我们首先要对ConcurrentModificationException 异常有所了解。当方法检测到对象的并发修改,但不允许这种修改时就抛出该异常。同时需要注意的是,该异常不会始终指出对象已经由不同线程并发修改,如果单线程违反了规则,同样也有可能会抛出改异常。

诚然,迭代器的快速失败行为无法得到保证,它不能保证一定会出现该错误,但是快速失败操作会尽最大努力抛出ConcurrentModificationException异常,所以因此,为提高此类操作的正确性而编写一个依赖于此异常的程序是错误的做法,正确做法是:ConcurrentModificationException 应该仅用于检测 bug。下面我将以ArrayList为例进一步分析fail-fast产生的原因。

从前面我们知道fail-fast是在操作迭代器时产生的。现在我们来看看ArrayList中迭代器的源代码:
这里写图片描述

从上面的源代码我们可以看出,迭代器在调用next()、remove()方法时都是调用checkForComodification()方法,该方法主要就是检测modCount == expectedModCount ? 若不等则抛出ConcurrentModificationException 异常,从而产生fail-fast机制。所以要弄清楚为什么会产生fail-fast机制我们就必须要用弄明白为什么modCount != expectedModCount ,他们的值在什么时候发生改变的。

expectedModCount 是在Itr中定义的:int expectedModCount = ArrayList.this.modCount;所以他的值是不可能会修改的,所以会变的就是modCount。modCount是在 AbstractList 中定义的,为全局变量:

这里写图片描述
那么他什么时候因为什么原因而发生改变呢?请看ArrayList的源码:
这里写图片描述
从上面的源代码我们可以看出,ArrayList中无论add、remove、clear方法只要是涉及了改变ArrayList元素的个数的方法都会导致modCount的改变。所以我们这里可以初步判断由于expectedModCount 得值与modCount的改变不同步,导致两者之间不等从而产生fail-fast机制。
其主要的逻辑还是防止在并发环境下所产生的错误。

fail-fast解决办法

方案一:在遍历过程中所有涉及到改变modCount值得地方全部加上synchronized或者直接使用Collections.synchronizedList,这样就可以解决。但是不推荐,因为增删造成的同步锁可能会阻塞遍历操作。

方案二:使用CopyOnWriteArrayList来替换ArrayList。推荐使用该方案。

CopyOnWriteArrayList为何物?ArrayList 的一个线程安全的变体,其中所有可变操作(add、set 等等)都是通过对底层数组进行一次新的复制来实现的。 该类产生的开销比较大,但是在两种情况下,它非常适合使用。

1:在不能或不想进行同步遍历,但又需要从并发线程中排除冲突时。
2:当遍历操作的数量大大超过可变操作的数量时。

遇到这两种情况使用CopyOnWriteArrayList来替代ArrayList再适合不过了。

那么为什么CopyOnWriterArrayList可以替代ArrayList呢?

第一、CopyOnWriterArrayList的无论是从数据结构、定义都和ArrayList一样。它和ArrayList一样,同样是实现List接口,底层使用数组实现。在方法上也包含add、remove、clear、iterator等方法。

第二、CopyOnWriterArrayList根本就不会产生ConcurrentModificationException异常,也就是它使用迭代器完全不会产生fail-fast机制。请看:
这里写图片描述
CopyOnWriterArrayList的方法根本就没有像ArrayList中使用checkForComodification方法来判断expectedModCount 与 modCount 是否相等。它为什么会这么做,凭什么可以这么做呢?我们以add方法为例:
这里写图片描述
CopyOnWriterArrayList的add方法与ArrayList的add方法有一个最大的不同点就在于,下面三句代码:
这里写图片描述

就是这三句代码使得CopyOnWriterArrayList不会抛ConcurrentModificationException异常。他们所展现的魅力就在于copy原来的array,再在copy数组上进行add操作,这样做就完全不会影响COWIterator中的array了。

所以CopyOnWriterArrayList所代表的核心概念就是:任何对array在结构上有所改变的操作(add、remove、clear等),CopyOnWriterArrayList都会copy现有的数据,再在copy的数据上修改,这样就不会影响COWIterator中的数据了,修改完成之后改变原有数据的引用即可。同时这样造成的代价就是产生大量的对象,同时数组的copy也是相当有损耗的。

abaqus2matlab的安装与使用:如何用matlab提取abaqus的odb结果 官网abaqus2matlab官网地址matlab社区地址matlab社区地址在这里可以看到.m文件的源码论文:Abaqus2Matlab: A suitable tool for finite element post-processingabaqus2matlab可以处理.inp、.fil、.odb三种类型的文件。.inp文件:处理功能就在于只是单纯的输出inp文件,由于我自己写了自己的函数,不需要用到这个功能。 阅读详情

相关推荐

利用featureCounts实现高效转录本定量:从比对到下游分析

本文详细介绍了利用featureCounts工具进行RNA-seq转录本定量的完整流程。从软件安装、输入文件准备,到核心命令参数解析与批量样本处理,再到将生成的计数矩阵无缝衔接至DESeq2进行差异表达分析,提供了从比对到下游分析的一站式实战指南。文章重点阐述了featureCounts在效率与易用性上的优势,并分享了常见问题排查与性能优化技巧,帮助研究者高效完成转录本定量这一关键步骤。

weixin_29069131的博客 317

fail-fast 机制是什么?(详解)

1. 介绍: fail-fast:快速失败系统,通常设计用于停止有缺陷的过程,这是一种理念,在进行系统设计时优先考虑异常情况,一旦发生异常,直接停止并上报。 举一个最简单的fail-fast例子: public int divide(int divisor, int dividend){ if (dividend == 0) { throw new RuntimeException("被除数不能为0"); //这里就是fail-fast的体现 } return

OYMNCHR的博客 9467

双有源桥DC-DC变换器:原理、软开关与移相控制深度解析

隔离型DC-DC变换器是电力电子系统的核心部件,通过高频变压器实现电气隔离与电压匹配,保障系统安全与灵活适配。其工作原理基于功率半导体器件的开关动作,通过调制策略控制能量传输。该技术的核心价值在于实现高效、高功率密度的电能转换,并支持双向能量流动,这对于提升系统整体能效和运行灵活性至关重要。在新能源储能、电动汽车V2G及数据中心供电等场景中,双向能量流成为刚性需求,推动了如双有源桥等先进拓扑的应用。本文聚焦于双有源桥这一实现高效双向隔离变换的“明星”方案,深入剖析其利用移相控制实现软开关的机理。通过分析谐振

weixin_34195142的博客 378

fail-fast 快速失败机制

1、什么是 fail-fast 维基百科中关于fail-fast的解释: 在系统设计中,快速失效系统一种可以立即报告任何可能表明故障的情况的系统。快速失效系统通常设计用于停止正常操作,而不是试图继续可能存在缺陷的过程。这种设计通常会在操作中的多个点检查系统的状态,因此可以及早检测到任何故障。快速失败模块的职责是检测错误,然后让系统的下一个最高级别处理错误。 其实,这是一种理念,fail-fast就是在做系统设计的时候先考虑异常情况,一旦发生异常,直接停止并上报。 举一个最简单的fail-fast

xiaoyuan_27的博客 2873

Oracle入门——基础语法篇

ROWID是Oracle中的一个伪列,用于唯一标识数据库中的每一行。在查询中,可以使用ROWID来定位和操作特定的行,例如,删除特定的行或更新特定的行。在Oracle中,子查询是指嵌套在另一个查询内部的查询语句,它可以作为主查询的一部分,用于提供额外的过滤条件、计算或数据源。在Oracle中,连接查询是通过使用JOIN子句将两个或多个表中的数据合并在一起,以获取满足特定条件的结果集。在Oracle数据库中,ROWID和ROWNUM都是用于对行进行标识和定位的伪列,它们在查询中的使用有一些不同之处。

麦当当的博客 3089

改善电流不匹配的级联电流镜布局设计 2002

模拟金属氧化物半导体 (MOS) 集成电路的性能在很大程度上取决于匹配精度的因素。 电流镜的匹配精度在模拟 IC 性能中尤为重要。 布局技术和器件尺寸被认为是可以在很大程度上改善匹配行为的主要因素。 尽管这些信息很重要,但对这两个因素的研究或研究有限。 在本文中,我们基于 Lan 等人 [1999] 提出的简单电流镜提出了一种新的级联电流镜布局技术。 Cascode电流镜的新布局在参数梯度存在的情况下改善了匹配特性。 讨论了跨晶体管有源区域的阈值梯度对电流镜匹配特性的影响。 使用 SPICE 仿真比较了新

Srfun的博客 4227

fail-fast快速失败机制

fail-fast俗称快速失败,是在多线程进行迭代操作时产生冲突的一种异常抛出机制,下面我们就由ArrayList来深入理解Java中的fail-fast机制. 1. fail-fast简介 “快速失败”也就是fail-fast,它是Java集合的一种错误检测机制。某个线程在对collection进行迭代时,不允许其他线程对该collection进行结构上的修改。 例如:假设存在两个线程(线程1、线程2),线程1通过Iterator在遍历集合A中的元素,在某个时候线程2修改了集合A的结构(是结构上面的修改,

码农翻身的博客 638

STK轨道仿真环境搭建实战:从地月系到多天体场景

本文详细介绍了STK轨道仿真环境搭建的实战指南,从基础的地月系统到复杂的多天体场景。通过逐步操作说明和实用技巧,帮助用户快速掌握STK软件的使用方法,提升轨道仿真效率,适用于航天任务设计和教学演示。

weixin_30312563的博客 397

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

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

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

智能车图像处理2-入门级分析1 ---基础扫线

PS :入门级文章适合新手,如果已经有基础可以去看进阶篇文章。

taiyuezyh的博客 7742

深度学习(五)迁移学习(实战:新数据预测+vgg16和聚类预测)

6、成功引入PCA数据降维技术,剔除了数据中的噪音信息、降低了模型复杂度、减少了模型训练时间,并最终提高了模型表现;gen=datagen.flow_from_directory(path,target_size=(224,224),batch_size=2,save_to_dir=dst_path,save_prefix='gen',save_format='jpg') # 生成图片大小224*224,bs产生多少组图像,存储路径和前缀。1、通过使用新数据,实现了模型的2次训练,达到了较好的预测效果;

weixin_37699342的博客 775

2026后端面试必考!Java集合硬核解析(一)(从ArrayList扩容到CopyOnWrite,建议收藏)

本文将为你带来一份Java集合面试题的深度解析指南。我将从Java集合体系结构与Collection/Collections的区别出发,逐步深入到List、Set、Map三大核心接口的本质差异。文章核心部分将详细拆解ArrayList与LinkedList的底层数据结构与线程安全问题,并最终系统总结Vector的历史局限性以及CopyOnWriteArrayList的底层原理。

专注AI与大模型技术,深耕NLP、RAG、Agent开发,分享Python机器学习与深度学习实战经验,助力技术成长。 435

Gbase 8a GDCA考试真题100%

本文整理一些Gbase 8a中非常易错得考试真题及答案,而且都是不好搜的。加粗的是正确答案。

打工之路,一路生花 4299

ArrayList源码深度剖析,从最基本的扩容原理,到魔幻的迭代器和fast-fail机制,你想要的这都有!!!

ArrayList源码深度剖析,包含基本的设计原理,扩容原理,迭代器源码剖析,fast-fail机制剖析,精彩内容,你想要的这里都有!!!

qq_45537774的博客 282

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Java 集合框架进阶——List 实现类深度解析与实战优化

摘要: Java集合框架中,List是最常用的有序集合接口。本文深度解析四大实现类: ArrayList:动态数组结构,随机访问O(1),扩容1.5倍,非线程安全,适合绝大多数场景; LinkedList:双向链表,头尾操作O(1),内存占用高,适合频繁增删场景; Vector:线程安全但性能差,已过时; CopyOnWriteArrayList:写时复制,读多写少并发场景首选。 优化建议:预分配容量、避免subList陷阱、选择高效遍历方式、批量操作优先。开发中95%场景推荐ArrayList,并发读多写

m0_57545130的博客 275

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Java 集合精讲:理解原理

本文深入解析Java集合框架的核心原理,重点涵盖底层数据结构和扩容机制,不涉及并发安全集合。主要内容包括: 集合框架体系:分为Collection(List、Set、Queue)和Map两大体系

留白Blank的博客 363

WINCC7.3破解文件

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

Java集合(1)

ArrayList、LinkedList和Vector的区别与ArrayList扩容机制 摘要 本文对比分析了Java集合框架中ArrayList、LinkedList和Vector的主要区别,重点讲解了ArrayList的扩容机制。ArrayList基于Object数组实现,查询快(O(1))但增删慢(O(n));LinkedList基于双向链表实现,增删快(O(1))但查询慢(O(n));Vector是线程安全的古老实现。ArrayList的扩容机制采用1.5倍增长策略,初始容量为10(JDK8采用懒加

2301_78547133的博客 270

从“混沌初开”到“有序统一”:Java集合框架发展历程与核心知识点详解

fail-fastfail-safe从JDK 1.2的初生牛犊,到如今JDK 21的成熟稳健,Java集合框架已经走过了近三十年的辉煌历程。它始于对混乱的“特设类”的统一,在社区探索中汲取养分,在泛型中涅槃重生,在并发浪潮中开疆拓土,在函数式编程中焕发新颜,在JDK 21中实现了有序集合的统一。它不仅是Java标准库中使用频率最高的API,更是一本生动的教科书,向我们展示了何为优秀的API设计:清晰、一致、可扩展、高性能。

King_model的博客 495

Java面试-fail-fast 机制原理与 ConcurrentModificationException

fail-fast。

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

java fail 方法_Java 集合系列04之 fail-fast总结(通过ArrayList来说明fail-fast的原理、解决办法)...

概要1 fail-fast简介fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fas...

weixin_31234793的博客 127

Java集合框架深度剖析 — 从源码看ArrayList、HashMap的设计与优化

本文深入解析Java集合框架中ArrayList和HashMap的实现原理。ArrayList基于动态数组,通过1.5倍扩容策略平衡空间效率;HashMap采用数组+链表/红黑树结构,优化哈希算法减少冲突。文章详细剖析了扩容机制、红黑树转换阈值(8/6)和Fail-Fast并发检测原理,通过性能对比表和使用场景分析,提供了集合选型、初始容量设置、哈希函数优化等实用建议,帮助开发者编写高性能代码。

七夜zippoe的博客 948

Java迭代器的 fail-fast 机制——为什么遍历时不能直接 remove?

本文对比了Java和Go语言在遍历集合时删除元素的差异。Java通过fail-fast机制(基于modCount和expectedModCount计数器)在检测到并发修改时会立即抛出ConcurrentModificationException异常,避免数据错乱。而Go语言由于设计哲学追求轻量,其range循环没有内置这种检查机制,需要开发者自行注意迭代安全。文章详细剖析了Java fail-fast的实现原理,解释了为何不能直接使用集合的remove方法而必须通过迭代器的remove操作,并提供了正确的删

fancyfor的博客 251

JUC并发—1.Java集合包底层源码剖析

此时再调用add()方法插入一个元素,也就是需要插入第11个元素,那么肯定是插入不进去的。虽然通过table[i]数组索引直接定位元素的时间复杂度是O(1),但如果链表存在大量元素,会是导致对该链表get()操作的性能急剧下降的。其中的分支代码"if ((p = tab[i = (n - 1) & hash]) == null)"的意思是:如果通过哈希寻址算法定位到的下标为i的数组元素为空(即tab[i]为空),那么就可以直接将一个新创建的Node对象放到数组的tab[i]这个位置。

mjunz的博客 1055

Java 集合框架高级特性与开发最佳实践

本文深入探讨Java集合框架的高级特性与开发实践,重点涵盖泛型约束、迭代器机制和Stream API集成三大核心内容。在泛型部分,详细解析了上限/下限通配符的使用场景和PECS原则(Producer Extends, Consumer Super),确保类型安全。迭代器机制章节剖析了Iterator接口的核心方法及安全遍历技巧,避免并发修改异常。最后,文章总结了集合开发中的最佳实践,包括空值处理、类型安全和并发安全等关键点,帮助开发者规避常见陷阱,提升代码质量。

今天比昨天更努力一点! 9396

Java集合框架(Java Collections Framework, JCF)简介

Java集合框架深度解析 摘要:本文全面剖析Java集合框架(JCF)的设计原理与实现细节。首先介绍集合框架的两大根接口体系(Collection和Map)及其核心设计思想。重点分析了List接口的两种实现:基于动态数组的ArrayList(详解扩容机制和Fail-Fast原理)和基于双向链表的LinkedList。针对Set接口,深入探讨了HashSet(哈希表实现)、LinkedHashSet(维护插入顺序)和TreeSet(红黑树实现)的特性与适用场景。通过性能对比和选型指南,帮助开发者根据具体需求选

百锦再的博客 936

Java集合框架深入解析:ArrayList & LinkedList

本文解析 Java 中 ArrayList 和 LinkedList 核心差异:ArrayList 基于动态数组,1.5 倍扩容、随机访问快(O (1))但增删慢,有 Fail-Fast 机制;LinkedList 基于双向链表,无需扩容,头尾增删快(O (1))但随机访问慢(O (n)),内存开销更高。选型优先 ArrayList,仅高频头尾操作 / 队列场景选 LinkedList。带有诸多代码解析以及代码注释解释

2301_80567343的博客 1125
上一篇: Java集合框架剖析(4)——LinkedList
下一篇: Java集合框架剖析(6)——Map架构
sicofield
博客等级 码龄18年 169粉丝 169原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值