一、背景

在常见的Java的非线程安全集合类中(如HashMap、ArrayList),经常可以在一些修改结构的操作(如Add)中看到实例变量 modCount++ ,来统计集合的修改次数。

从注释也可以看出,该字段是为 fail-fast(快速失败)机制服务。

二、简介

fail-fast 机制是能立刻报告任何可能导致失败的错误检测机制。

在java集合框架中表现为:当构建迭代器时,起初expectedModCount = modCount,当修改了该集合时,则该集合modCount++,随后迭代器在迭代下个元素时,会发现当前的modCount值与期望值expectedModCount不符,便会抛出ConcurrentModificationException异常,以避免数据不同步带来的麻烦。

注:

  1. 使用迭代器的remove()方法不会抛出异常,看源码可知在其中重新设置expectedModCount。
  2. 该机制不保证存在非同步并发修改时一定会抛出异常,只是尽最大努力去抛出该异常,因此最好不要依赖于该异常去写程序,而只是用于debug阶段。

官方注释:

Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.

三、两种出现场景

3.1 单线程环境

在遍历集合的过程中,调用了集合修改方法。

例:

class Test{
public static void main(String[] args){
ArrayList<Integer> list = new ArrayList();
list.add(1); list.add(2); list.add(3); Iterator itr = list.iterator();
while(itr.hasNext()){
System.out.println(itr.next());// 1 \n 2 \n 3
itr.remove(); //后续不会抛出异常
}
System.out.println(list.toString());// 输出:[]
list.add(1); list.add(2); list.add(3); itr = list.iterator();
while(itr.hasNext()){
Object i = itr.next();
System.out.println(i);
list.remove(i); //后续next时会抛出异常
}
}
}

3.2 多线程环境

一个线程在遍历该集合时,另一个线程修改了该集合结构。

    ArrayList<Integer> list = new ArrayList();
list.add(1); list.add(2); list.add(3); for(Integer i: list){
new Thread(() -> {
list.add(4);
}).run();
System.out.println(i);
}

四、迭代器源码解析

以ArrayList对Iterator的实现为例:

    private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount; // 期望的modCount值即为创建迭代器时的modCount值 Itr() {} public boolean hasNext() { // hasNext 并不抛异常
return cursor != size;
} @SuppressWarnings("unchecked")
public E next() {
checkForComodification(); //首先检查expectedModCount是否一致
// …省略
} public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification(); try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount; //迭代器remove后不抛异常的原因,更新 expectedModCount
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
} /** 检查 expectedModCount 与 当前 modCount是否一致,否则抛异常*/
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}

参考:

https://www.geeksforgeeks.org/fail-fast-fail-safe-iterators-java/

https://blog.csdn.net/u014692324/article/details/78577130

从 modCount 看 java集合 fail-fast 机制的更多相关文章

  1. 从源码看Java集合之ArrayList

    Java集合之ArrayList - 吃透增删查改 从源码看初始化以及增删查改,学习ArrayList. 先来看下ArrayList定义的几个属性: private static final int ...

  2. Java fail-fast 与 fail-safe 机制对比

    关于fail-fast参考这篇文章:   从 modCount 看 java集合 fail-fast 机制 一.fail-safe概述以及与fail-fast区别 首先 fail-safe 并不属于J ...

  3. Java集合框架——容器的快速报错机制 fail-fast 是什么?

    前言:最近看 java 集合方面的源码,了解到集合使用了 fail-fast 的机制,这里就记录一下这个机制是什么,有什么用,如何实现的. 一.fail-fast 简介 fail-fast 机制,即快 ...

  4. Java集合框架中的元素

    之前有一篇笔记,讲的是集合和泛型,这几天看Java集合中几个接口的文档,思绪非常混乱,直到看到Oracle的“The Collections Framwork”的页面,条理才清晰些,现在进行整理. 一 ...

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

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

  6. Java 集合 fail-fast机制 [ 转载 ]

    Java 集合 fail-fast机制 [转载] @author chenssy 摘要:fail-fast产生原因.解决办法 在JDK的Collection中我们时常会看到类似于这样的话: 例如,Ar ...

  7. Java集合详解3:Iterator,fail-fast机制与比较器

    Java集合详解3:Iterator,fail-fast机制与比较器 今天我们来探索一下LIterator,fail-fast机制与比较器的源码. 具体代码在我的GitHub中可以找到 https:/ ...

  8. Java集合详解3:一文读懂Iterator,fail-fast机制与比较器

    <Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...

  9. Java集合最全解析,学集合,看这篇就够用了!!!

    在看集合类之前, 我们要先明白一下概念: 1.数据结构 (1):线性表 [1]:顺序存储结构(也叫顺序表) 一个线性表是n个具有相同特性的数据元素的有限序列.数据元素是一个抽象的符号,其具体含义在不同 ...

随机推荐

  1. Cognos报表验证(添加字段)

    1.打开后台Cognos 链接远程后台Cognos 2.打开要验证的报表 3.给右边的sql语句加个空格或者换行点击验证 4.查看业务视图中是否已经添加该字段 双击维度或者度量(添加字段所在的分类) ...

  2. HDU 5410 CRB and His Birthday (01背包,完全背包,混合)

    题意:有n种商品,每种商品中有a个糖果,如果买这种商品就送多b个糖果,只有第一次买的时候才送.现在有m元,最多能买多少糖果? 思路:第一次买一种商品时有送糖果,对这一次进行一次01背包,也就是只能买一 ...

  3. VINS-Fusion代码阅读(四)

    pts_i和pts_j:具体指什么含义?(分别为第l个路标点在第i, j个相机归一化相机坐标系中的观察到的坐标,P¯¯¯cil \bar{P}^{c_i}_l Pˉ lc i​ ​ 和 P¯¯¯cjl ...

  4. XtraBackUp 热备份工具

    是一款强大的在线热备份工具 备份的过程中,不锁表 使用percona-xtrabackup-24-2.4.7-1.el7.x86_64.rpm yum源安装: 1.安装Percona的库:       ...

  5. 关于sigleton模式

    单例模式的要点有三个:一是某个类只能有一个实例:二是它必须自行创建这个实例:三是它必须自行向整个系统提供这个实例. 从具体实现角度来说,就是以下三点:一是单例模式的类只提供私有的构造函数,二是类定义中 ...

  6. 【原创翻译】链接DLL至可执行文件---翻译自MSDN

    可执行文件.exe链接(或加载)DLL有以下两种形式: 隐式链接 显式链接 隐式链接是指静态加载或在程序加载时动态链接. 通过隐式链接,在使用DLL时,可执行文件链接到一个由生成DLL的人提供的导入函 ...

  7. executeFind(XXX) is undefined for the type hibernateTemplate(大概是这个错误吧)

    两句话,jar包版本不一样,类中包含的方法可能有改变. 出错时用的是spring5.x版本,但是没有找到我的api.(不记得放在那里了),所以换了spring的版本(换成了spring3.x).问题解 ...

  8. 制作SD更新系统时和用mfgtool工具烧录时,文件如何替换?

    制作SD更新系统时和用mfgtool工具烧录时,文件如何替换? 答:制作SD更新系统时,请按照需求选择不同mfgimages-myd*文件夹.每个文件夹里面有一个Manifest文件, 里面规定了ub ...

  9. Elasticsearch document深度剖析

    1. 针对Elasticsearch并发冲突问题,ES内部是如何解决的? 1)ES内部是线程异步并发修改的,是基于_version版本号进行乐观锁并发控制的: 2)若后修改的先到了,那么修改后版本发生 ...

  10. 896. Monotonic Array@python

    An array is monotonic if it is either monotone increasing or monotone decreasing. An array A is mono ...