fail-safe fail-fast知多少

简介

我们在使用集合类的时候,通常会需要去遍历集合中的元素,并在遍历中对其中的元素进行处理。这时候我们就要用到Iterator,经常写程序的朋友应该都知道,在Iterator遍历的过程中,是不能够修改集合数据的,否则就会抛出ConcurrentModificationException。

因为ConcurrentModificationException的存在,就把Iterator分成了两类,Fail-fast和Fail-safe。

Fail-fast Iterator

Fail-fast看名字就知道它的意思是失败的非常快。就是说如果在遍历的过程中修改了集合的结构,则就会立刻报错。

Fail-fast通常在下面两种情况下抛出ConcurrentModificationException:

  1. 单线程的环境中

如果在单线程的环境中,iterator创建之后,如果不是通过iterator自身的remove方法,而是通过调用其他的方法修改了集合的结构,则会报错。

  1. 多线程的环境中

如果一个线程中创建了iterator,而在另外一个线程中修改了集合的结构,则会报错。

我们先看一个Fail-fast的例子:

        Map<Integer,String> users = new HashMap<>();

        users.put(1, "jack");
users.put(2, "alice");
users.put(3, "jone"); Iterator iterator1 = users.keySet().iterator(); //not modify key, so no exception
while (iterator1.hasNext())
{
log.info("{}",users.get(iterator1.next()));
users.put(2, "mark");
}

上面的例子中,我们构建了一个Map,然后遍历该map的key,在遍历过程中,我们修改了map的value。

运行发现,程序完美执行,并没有报任何异常。

这是因为我们遍历的是map的key,只要map的key没有被手动修改,就没有问题。

再看一个例子:

Map<Integer,String> users = new HashMap<>();

        users.put(1, "jack");
users.put(2, "alice");
users.put(3, "jone"); Iterator iterator1 = users.keySet().iterator(); Iterator iterator2 = users.keySet().iterator();
//modify key,get exception
while (iterator2.hasNext())
{
log.info("{}",users.get(iterator2.next()));
users.put(4, "mark");
}

上面的例子中,我们在遍历map的key的同时,对key进行了修改。这种情况下就会报错。

Fail-fast 的原理

为什么修改了集合的结构就会报异常呢?

我们以ArrayList为例,来讲解下Fail-fast 的原理。

在AbstractList中,定义了一个modCount变量:

protected transient int modCount = 0;

在遍历的过程中都会去调用checkForComodification()方法来对modCount进行检测:

      public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}

如果检测的结果不是所预期的,就会报错:

        final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}

在创建Iterator的时候会复制当前的modCount进行比较,而这个modCount在每次集合修改的时候都会进行变动,最终导致Iterator中的modCount和现有的modCount是不一致的。

        public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification(); try {
AbstractList.this.set(lastRet, e);
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}

注意,Fail-fast并不保证所有的修改都会报错,我们不能够依赖ConcurrentModificationException来判断遍历中集合是否被修改。

Fail-safe Iterator

我们再来讲一下Fail-safe,Fail-safe的意思是在遍历的过程中,如果对集合进行修改是不会报错的。

Concurrent包下面的类型都是Fail-safe的。看一个ConcurrentHashMap的例子:

Map<Integer,String> users = new ConcurrentHashMap<>();

        users.put(1, "jack");
users.put(2, "alice");
users.put(3, "jone"); Iterator iterator1 = users.keySet().iterator(); //not modify key, so no exception
while (iterator1.hasNext())
{
log.info("{}",users.get(iterator1.next()));
users.put(2, "mark");
} Iterator iterator2 = users.keySet().iterator();
//modify key,get exception
while (iterator2.hasNext())
{
log.info("{}",users.get(iterator2.next()));
users.put(4, "mark");
}

上面的例子完美执行,不会报错。

总结

Fail-fast 和 Fail-safe 是集合遍历的重要概念,希望大家能够掌握。

本文的例子https://github.com/ddean2009/learn-java-streams

欢迎关注我的公众号:程序那些事,更多精彩等着您!

更多内容请访问 www.flydean.com

fail-safe fail-fast知多少的更多相关文章

  1. Fail Fast and Fail Safe Iterators in Java

    https://www.geeksforgeeks.org/fail-fast-fail-safe-iterators-java/ Fail Fast and Fail Safe Iterators ...

  2. fail fast和fail safe策略

    优先考虑出现异常的场景,当程序出现异常的时候,直接抛出异常,随后程序终止 import java.util.ArrayList; import java.util.Collections; impor ...

  3. 快速失败(fail—fast)和 安全失败(fail—safe)

    快速失败(fail-fast) 在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的结构进行了修改(增加.删除),则会抛出Concurrent Modification Exception. 原理 ...

  4. [Oracle]Oracle Fail Safe 与 SQLNET.AUTHENTICATION_SERVICES关系

    现象: 在使用 OFS (Oracle Fail Safe)的环境中,把数据库的 SQLNET.AUTHENTICATION_SERVICES 从 NTS 改为 NONE之后,当从 Oracle Fa ...

  5. Java集合框架中的快速失败(fail—fast)机制

      fail-fast机制,即快速失败机制,是java集合框架中的一种错误检测机制.多线程下用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加.删除),则会抛出Concurre ...

  6. 【Codeforces163E】e-Government AC自动机fail树 + DFS序 + 树状数组

    E. e-Government time limit per test:1 second memory limit per test:256 megabytes input:standard inpu ...

  7. 【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2022  Solved: 1158[Submit][Sta ...

  8. 【bzoj2434-阿狸的打字机】AC自动机+fail树+优化

    http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23083 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一 ...

  9. CF 163E. e-Government ac自动机+fail树+树状数组

    E. e-Government 题目: 给出n个字符串,表示n个人名,有两种操作: ?string ,统计字符串string中出现的属于城市居民的次数. +id,把编号为id的人变为城市居民,如果已经 ...

  10. AC自动机相关Fail树和Trie图相关基础知识

    装载自55242字符串AC自动机专栏 fail树 定义 把所有fail指针逆向,这样就得到了一棵树 (因为每个节点的出度都为1,所以逆向后每个节点入度为1,所以得到的是一棵树) 还账- 有了这个东西, ...

随机推荐

  1. Python面向对象之异常处理

    1:什么是异常 异常就是在我们的程序在运行过程中由于某种错误而引发Python抛出的错误: 异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序 ...

  2. Aircoinst 三层架构ASP.NET开源

    <注意! 本源码为我本人所写,可能有点烂.仅供学习使用,请勿进行商业用途~!> <本源码永久归于MineLSG 及 Aircoinst_慈 所拥有> 使用方法:直接拷贝 一.结 ...

  3. vue 动态添加body背景图片

    <script> export default {   data () {     return {      bodyBgImage: 'url(' + require('../asse ...

  4. 如何将 .NetFramework WebApi 按业务拆分成多个模块

    在 .NetFramework 中使用 WebApi ,在不讨论 微服务 的模式下,大部分都是以层来拆分库的 : 基础设施 数据存储层 服务层 WeApi 层 一些其它的功能库 项目结构可能会像下面这 ...

  5. qt creator源码全方面分析(3-9)

    依赖分析图 我们对库和插件的依赖性进行分析,并画图如下,稍微省略了一些插件,画出来太乱了,核心的都在图中了. 原创造福大家,共享改变世界 献出一片爱心,温暖作者心灵

  6. windows的注册表有什么用?

    注册表是什么 注册表是Microsoft Windows中的一个重要的数据库,用于存储系统和应用程序的设置信息.早在Windows 3.0推出OLE技术的时候,注册表就已经出现.随后推出的Window ...

  7. 家庭版记账本app开发完成

    经过这几天关于android的相关学习,对于家庭版记账本app以及开发结束. 实现的功能为:用户的注册.登录.添加支出账单.添加收入账单.显示所有的该用户的账单情况(收入和支出).生产图表(直观的显示 ...

  8. node+express+mysql实现简单的数据增删改查

    前提 电脑已经安装了node,express,mysql. 实现步骤 1.新建数据库表 附数据表结构: 2.创建exprss项目 express -e myapp  新建一个以ejs为模板的expre ...

  9. 统计分析_集中趋势and离散程度

    1.数组的集中趋势-如何定义数组的中心 1.1 常用几下几个指标来描述一个数组的集中趋势 均值-算术平均数 . 中位数-将数组升序或降序排列后,位于中间的数. 众数-数组中出现最多的数. 1.2 指标 ...

  10. Python库-Matplotlib

    Matplotlib官网https://matplotlib.org,Matplotlib是一个Python的2D绘图库. 可视化是整个数据分析的关键辅助工具,可以清晰的理解数据. 折线图(用于显示数 ...