从ConcurrentModificationException异常唠唠fail-fast & fail—safe机制

本文介绍了Java中Fail-fast和Fail-safe两种迭代器遍历机制的区别。Fail-fast机制会在遍历过程中若集合被修改,则抛出异常;而Fail-safe机制通过复制集合内容进行遍历,避免异常抛出,但无法获取最新的集合状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

区别

Fail-fast

Fail-safe

含义

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

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

原理

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

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

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

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

场景

java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)。

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

具体实现

HashMap,Vector,ArrayList,HashSet

CopyOnWriteArrayList,ConcurrentHashMap

 

`ConcurrentModificationException` 是 Java 中的一个运行时异常,通常发生在我们尝试修改集合(如 `ArrayList`, `HashMap` 等)的同时有另一个线程或迭代器正在访问该集合的情况。为了保证数据的一致性和防止潜在的数据损坏问题,Java 集合框架引入了 fail-fast 机制。 ### Fail-Fast 机制 Fail-fast 意味着“快速失败”。当检测到对集合进行并发修改时(例如,在遍历过程中直接添加、删除元素),就会抛出 `ConcurrentModificationException` 来立即报告错误而不是继续执行可能导致不确定结果的操作。这有助于开发者尽快发现并修复程序中的同步问题。 #### 典型场景 - **单线程环境**:即使是在单个线程内,如果在使用迭代器遍历时通过其他方式改变了列表的内容(除了 Iterator 自身提供的 remove/add 方法外),也会触发此异常- **多线程环境**:多个线程同时读取和更新相同的集合而未采取适当的锁机制保护资源安全的情况下会发生这种情况。 ### 解决方案 为了避免这个问题可以考虑以下几个方面: 1. 使用 synchronized 关键字手动加锁来控制对共享对象的访问; 2. 利用并发包下的容器类比如 ConcurrentHashMap 或 CopyOnWriteArrayList 这些专门设计用于处理高并发情况的安全结构; 3. 如果只是简单地想阻止外部改变 List 内容,则可以用 Collections.unmodifiableList() 包装原 list 得到只读版本; 4. 在一些特定场合下还可以选择采用更高效但稍微宽松一点的做法 - 比如允许有限度内的延迟刷新等策略,但这需要根据实际需求权衡利弊后再做决定。 总之,理解如何避免和妥善解决 `ConcurrentModificationException` 对编写稳定可靠的 Java 应用非常重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值