一、背景

在常见的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. 为Qt添加SSL支持

    目标:为Qt添加SSL支持,使得应用可以发送HTTPS请求 环境:win7,Qt4.8.6 步骤: 1.到http://slproweb.com/products/Win32OpenSSL.html下 ...

  2. 【整理】解决vue不相关组件之间的数据传递----vuex的学习笔记,解决报错this.$store.commit is not a function

    解决vue不相关组件之间的数据传递----vuex的学习笔记,解决报错this.$store.commit is not a function https://www.cnblogs.com/jaso ...

  3. JS怎么创建一个类?

    15. JS怎么创建一个类? 方式1 : var obj = new Object(); 方式2 : var obj = {}; 16.JS的typeof返回哪些数据类型? string.number ...

  4. Linux 常用命令:解压缩

    目录 Linux 常用命令:解压缩 说明 tar 涉及参数说明: 压缩 解压 zip压缩 涉及参数说明: uzip解压 涉及参数说明: gzip 涉及参数说明: 压缩率比较 Linux 常用命令:解压 ...

  5. [IOS初学]ios 第一篇 storyboard 与viewcontroller的关系 - Zoe_J

    时间 2014-07-27 16:08:00  博客园-所有随笔区 原文  http://www.cnblogs.com/zoe-j/p/3871501.html 主题 StoryBoard 学习了一 ...

  6. Manjaro安装SS客户端

    首先安装shadowsocks-libev sudo pacman -S shadowsocks-libev 然后编辑配置文件 vim /etc/shadowsocks/config.json { & ...

  7. 离散数学-集合的交并差集运算--STL-set类

    代码其实很简单,我们只需要知道set类的使用方法就可以了,比如迭代器的定义( set<T>::iterator it=a.begin() ),和简单的insert函数插入,以及find函数 ...

  8. C/C++连接MySQL数据库执行查询

    1. 简介: 使用C/C++连接MySQL数据库执行增删改查操作,基本就是围绕以下两个文件展开: mysql.h(此头文件一般在MySQL的include文件夹内,如 D:\MySQL\mysql-5 ...

  9. js 对象细节

    原型和原型链 在对象自身身上找不到指定属性时,就会到这个对象的原型__proto__上找,原型也是指向一个对象,在这个对象上还找不到对应属性,则继续到原型上来找...以上过程形成原型链. 访问对象的原 ...

  10. 前端面试绝对会考的JS问题!【已经开源】

    写在前面 [前端指南]前端面试库已经开源,正在完善之中 [x] css问题 [x] html问题 [x] javascript问题 github地址 https://github.com/nanhup ...