【阿里面试题】fail-fast、fail-safe一套给你讲全!!!






什么是fail-fast、fail-safe


fail-fast(快速失败) 和 fail-safe(安全失败) 是 Java集合中常见的错误检测机制,通常出现在集合遍历过程中。

fail-safe允许在遍历的过程中对容器中的数据进行修改,而fail-fast则不允许。

java.util下的所有集合类都是 fail-fast 机制,而 java.util.concurrent 包下的所有集合类都是 fail-safe机制。




java.util包下

ArrayList

在这里插入图片描述

Vector

在这里插入图片描述

HashMap

在这里插入图片描述

HashTable

在这里插入图片描述

可以看到在 java.util包下,无论你是线程安全的集合类还是不安全的集合类,在遍历过程中删除元素都会报 java.util.ConcurrentModificationException 异常 ,即并发修改异常。

为什么会报这种错误?

我们先来看看源码,以 ArrayList 为例

在这里插入图片描述

在这里插入图片描述

这个 modCount 变量 可能小伙伴们平时没有注意到过,这个变量其实是记录着的当前集合的一个修改次数,没调用一次add方法和remove方法的话,modCount就会加一。

在这里插入图片描述

说到这其实已经很明白了,但还要给大家说个知识点,那就是 foreach的原理,下面是代码及反编译之后的结果



foreach 底层原理

在这里插入图片描述

我们可以看到其实 foreach遍历其实优化成了调用迭代器遍历,说到这我再给大家说一说 list 的iterator方法吧

list的iterator()方法原理

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

总结一下吧

为什么一边遍历一遍删除会报错?

因为 list 内部存储一个名为 modCount的变量,它记录着集合的修改次数,而通过foreach遍历(即迭代器遍历)的时候,迭代器内部会维护一个初始值为0的游标 cursor,当cursor等于size的时候就会退出遍历,而迭代器每次调用next()方法时,会去调用一个checkForComodification()方法,而这个方法就是检查你的modCount的次数是否被改变,如果改变了说明被修改了则报错 ConcurrentModificationException;


java.util.concurrent包下

在这里插入图片描述

在这里插入图片描述

可以看到在 java.util.concurrent包下,在遍历过程中删除元素,都没有报错



如何解决

除了使用 java.util.concurrent 包下的集合类之外,还可以使用 迭代器进行遍历操作(当然如果实在多线程环境下还需要加锁)。

在这里插入图片描述

可以看见删除失败,成功遍历(要调用迭代器的 remove方法),而foreach之所以报错是因为还是调用的 list本身的remove方法,这就是区别。

为什么呢?

之前有一个字段 lastRet 我没有解释道,现在可以跟大家说,这个字段根据我的理解其实就是记录着当前元素的索引,我们可以看到 next()方法,开始用 i 记录游标,最后返回元素让 lastRet = i 因为返回的时当前元素,所以 lastRet 记录的也是当前元素的索引

再看 remove方法,由于lastRet保存着当前元素的索引(迭代器中没有remove(下标值)这个重载方法),所以直接调用list本身的remove方法传入下标值据可以删除了,而且删除之后更新 cursor、lastRet、和expectedModCount(调用list的removce方法modCount会++),这样的话对于下一次next方法来说没有什么影响,因为list本身的remove方法会涉及到元素的移动,

在这里插入图片描述

画图不够熟练,想明白还是很简单的,大家多看一下

顺带一提为什么java.util.concurrent包下的集合类也没报错,以CopyOnWriteArrayList为例吧

在这里插入图片描述

重点在remove方法

在这里插入图片描述

对于元素的删除操作是在新数组上完成的,所以当前集合不会修改,所以不会报错。



尾言

我是 Code皮皮虾,一个热爱分享知识的 皮皮虾爱好者,未来的日子里会不断更新出对大家有益的博文,期待大家的关注!!!

创作不易,如果这篇博文对各位有帮助,希望各位小伙伴可以一键三连哦!,感谢支持,我们下次再见~~~

分享大纲

大厂面试题专栏


Java从入门到入坟学习路线目录索引


开源爬虫实例教程目录索引

更多精彩内容分享,请点击 Hello World (●’◡’●)


在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值