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. Java第七天,类的继承

    面向对象编程的三大特征: 封装.继承.多态 今天我们学习继承! 继承是多态的前提,如果没有继承就没有多态. 继承主要解决的问题就是共性抽取(将许多类共有的特性便作父类,这样可以较大程度的优化代码). ...

  2. "首字母变大写"组件:<capitalize> —— 快应用组件库H-UI

     <import name="capitalize" src="../Common/ui/h-ui/text/c_text_capitalize"> ...

  3. 【课程学习】课程2:十行代码高效完成深度学习POC

    本文用户记录黄埔学院学习的心得,并补充一些内容. 课程2:十行代码高效完成深度学习POC,主讲人为百度深度学习技术平台部:陈泽裕老师. 因为我是CV方向的,所以内容会往CV方向调整一下,有所筛检. 课 ...

  4. 软件包管理rpm和yum

    rpm的使用: 安装的包相关包信息会保存在/var/lib/rpm目录下的文件中 安装参数: -i install安装 -v 显示详细信息 -h 打印####号 -V 校验软件包,会到/var/lib ...

  5. 第一章:shell脚本初入门

    1.shell脚本中的source或者.空格再加上文件,表示加载文件中的命令及语句(困惑多时终于解开^-^) 2.脚本开头书写好作者版本等信息,方便维护:流程语句提前把格式写好,防止遗漏 3.定义字符 ...

  6. Spring 下,关于动态数据源的事务问题的探讨

    开心一刻 毒蛇和蟒蛇在讨论谁的捕猎方式最高效. 毒蛇:我只需要咬对方一口,一段时间内它就会逐渐丧失行动能力,最后死亡. 蟒蛇冷笑:那还得等生效时间,我只需要缠住对方,就能立刻致它于死地. 毒蛇大怒:你 ...

  7. 解决Jquery中click里面包含click事件,出现重复执行的问题

    出现问题的代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.o ...

  8. java中如何理解:其他类型 + string 与 自增类型转换和赋值类型转换

    java中如何理解:其他类型 + string 与 自增类型转换和赋值类型转换 一.字符串与其他类型连接 public class DemoString{ public static void mai ...

  9. 全平台阅读器 StartReader

    前段时间在网上闲逛, 发现了一款全平台阅读器 StartReader, 用了一阵子感觉还不错,网址是: https://www.startreader.com/ 感觉这款阅读器是程序员的福音,it人员 ...

  10. Redis Linux安装+配置

    1.进入指定目录,下载资源(也可本地下载后复制到指定目录) wget http://download.redis.io/releases/redis-5.0.5.tar.gz 2.解压到指定目录 ta ...