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

本文详细介绍了Java集合框架中的fail-fast(快速失败)和fail-safe(安全失败)机制。fail-fast机制在单线程和多线程情况下可能会抛出`ConcurrentModificationException`,而fail-safe则通过复制集合内容来避免此类异常,但无法获取遍历期间的集合修改。在Java.util和java.util.concurrent包下的容器分别遵循这两种机制。

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

fail-fast机制(快速失败):

ConcurrentModificationException发生在Collection集合使用迭代器遍历时,使用了集合类提供的修改(增加、删除)集合内容方法报错,或者由于多线程操作导致。

1.单线程情况
  • modCount表示当前集合修改的次数,也可以认为是实际对象的个数。
  • ecpectedModCount是迭代器记录当前集合的修改次数。
1.1抛出上述异常的主要原因:

当调用容器的iterator()方法返回Iterator对象时,把容器中包含对象的个数赋值给了一个变量(ecpectedModCount = modCount),在调用next()方法时会比较ecpectedModCount 与modCount的值是否相等,若二者不相等,则会抛出该异常。

1.2解决方法:

在遍历过程中把需要删除的对象保存到一个集合中,等遍历结束后再调用removeAll()方法来删除,或者使用iterator.remove()方法。

1.3意义:

快速失败策略保证了所有用户在进行迭代遍历集合时,拿到的数据一定时最新的数据。(避免“脏读”产生)

1.4注意:

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

1.5场景:

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

2.多线程情况
2.1解决方法:
  • a. 在JDK1.5版本引入线程安全的容器,比如ConcurrentHashMap和CopyOnWriteArrayList等。可以使用这些线程安全的容器来代替非线程安全的容器。
  • b. 在使用迭代器遍历容器时对容器的操作放到sychronized代码块中,但是当引用程序并发程度比较高时,这会严重影响程序的性能。
fail-safe(安全失败):
1.原理:

采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发ConcurrentModificationException。

2.缺点:

基于拷贝内容的优点是避免了ConcurrentModificationException,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。(我认为这是一项掩耳盗铃的操作)

3.场景:

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

4.总结:

以后在迭代器遍历时不要修改集合内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值