AbstractList类中有一个属性

protected transient int modCount = 0;

api中对它的描述是:

  • 此列表已被结构修改的次数。 结构修改是改变列表大小的那些修改,或以其他方式扰乱它,使得正在进行的迭代可能产生不正确的结果。
  • 该字段由迭代器和列表迭代器实现使用,由iteratorlistIterator方法返回。 如果该字段的值意外更改,迭代器(或列表迭代器)将抛出一个ConcurrentModificationException响应next , remove , previous , setadd操作。 这提供了fail-fast行为,而不是面对在迭代期间的并发修改的非确定性行为

我的理解是,modCount表示了当前列表结构被修改的次数,在调用迭代器操作时,则会检查这个值,如果发现已更改,抛出异常

不过需要注意的是transient修饰意味着这个属性不会被序列化,而且modCount并没有被voliate修饰,也就是它不能保证在线程之间是可见的

从ArraytList源码中可以发现,add,remove,clear等方法实现时,均添加了modCount++;操作,例如clear方法:

public void clear() {modCount++;// clear to let GC do its workfor (int i = 0; i < size; i++)elementData[i] = null;size = 0;}

在arraylist中调用迭代器是通过内部类实现的:

public Iterator<E> iterator() {return new Itr();}

在这个内部类中,同样维护了一个类似modCount的变量

int expectedModCount = modCount;

并提供了检测方法

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

这个检测方法在迭代器中类似next方法里面作为首先需要判断的条件

@SuppressWarnings("unchecked")public E next() {checkForComodification();int i = cursor;if (i >= size)throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i + 1;return (E) elementData[lastRet = i];}

我们综合以上,就可以得出,

在使用迭代器遍历arraylist时,会初始化一个和modCount相等的变量,如果在迭代过程中,arraylist中发生了类似add这种改变结构的操作(modCount改变),导致modCount != expectedModCount,那么会抛出一个异常ConcurrentModificationException,即产生fail-fast事件

产生fail-fast有两种原因:

1.单线程情况下,迭代的过程中,调用类似add方法,但是一般不会这样做

     ArrayList<Integer> al = new ArrayList<>();for(int i=0;i<10;i++)al.add(i);Iterator<Integer> it = al.iterator();while(it.hasNext()) {System.out.println(it.next());if(!it.hasNext())al.add(10);}    

2.主要发生在多线程情况下,例如让线程1迭代,线程2修改,就有可能会出现

        final ArrayList<Integer> al = new ArrayList<>();for(int i=0;i<10;i++)al.add(i);    new Thread(new Runnable() {            @Overridepublic void run() {Iterator<Integer> it = al.iterator();while(it.hasNext()) {System.out.print(it.next()+" ");}                }}).start();        new Thread(new Runnable() {                    @Overridepublic void run() {al.remove(6);        }                    }).start();

如果抛出异常,就类似这个样子:

0 1 Exception in thread "Thread-0" java.util.ConcurrentModificationExceptionat java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)at java.util.ArrayList$Itr.next(ArrayList.java:859)at com.rw.importword.utils.Text$1.run(Text.java:19)at java.lang.Thread.run(Thread.java:748)

但是也有可能不抛出异常:

根据输出结果来看,al的结构已经改变,但是没有抛出异常

至于原因我想是:

modCount没有被voliate修饰,在线程之间不可见,可能某一个时机,线程2中remove操作改变的modCount值并没有及时写到内存中,线程1中迭代器获取的modCount值仍然是之前的值

由此可以得出,fail-fast机制,是一种错误检测机制。它只能被用来检测错误,因为JDK并不保证fail-fast机制一定会发生。

转载于:https://www.cnblogs.com/NextLight/p/9592069.html

通过ArrayList对modCount的操作分析fail-fast 机制相关推荐

  1. Java - Java集合中的快速失败Fail Fast 机制

    文章目录 什么是 fail-fast 源码解读 Itr 为什么对集合的结构进行修改会发生并发修改异常-源码分析 修改方法之 remove 修改方法之 add 案例分享 [案例一] [案例二] [案例三 ...

  2. Fail - Fast机制

    平常在使用集合的时候肯定会遇到过遍历删除集合中的某些元素,哪么在进行操作的时候大家有 没有遇到过什么问题呢?最近在使用集合进行遍历删除元素的时候,我就碰到了这个异常:java.util.Concurr ...

  3. Java - Java集合中的安全失败Fail Safe机制 (CopyOnWriteArrayList)

    文章目录 Pre 概述 fail-safe的容器-CopyOnWriteArrayList add remove函数 例子 缺陷 使用场景 Pre Java - Java集合中的快速失败Fail Fa ...

  4. 【转载】ArrayList 中数据删除 fail fast

    2019独角兽企业重金招聘Python工程师标准>>> 本文转载自http://shift-alt-ctrl.iteye.com/blog/1839147 在循环arrayLlist ...

  5. 什么是Fail Fast和Fail Safe?

    这里是目录标题 1. Fail Fast a. 概念 b. 原理 c. 关注点 d. 注意 2. Fail Safe a. 概念 b. 原理 3. Fail Fast 和 Fail Safe的区别 1 ...

  6. 聊聊hikari与tomcat jdbc pool的fail fast

    序 本文主要研究在中途数据库挂的情况下,hikari与tomcat jdbc pool的fail fast情况. 实验代码 @Testpublic void testDatabaseDownAndUp ...

  7. 【springcloud问题】Could not locate PropertySource and the fail fast property is set, failing

    问题描述:使用springcloud的本地配置中心时出现:Could not locate PropertySource and the fail fast property is set, fail ...

  8. Fail Fast与Fail Safe的区别

    Fail Fast Fail Fast Iterator在遍历集合时,若该集合发生了结构性的改变,则将抛出 ConcurrentModification 异常.例如: Map<String, S ...

  9. Java Review - ArrayList 源码解读

    文章目录 概述 方法的执行效率 源码剖析 底层数据结构 -数组 构造函数 自动扩容机制 set() get add()/addAll() remove() trimToSize() indexOf() ...

最新文章

  1. 聚焦基础科学 引领未来发展
  2. 自由主义者的周一和周五
  3. Python Selenium 常用方法总结
  4. 112. Path Sum 路径总和
  5. 万字长文深度解析python 单元测试
  6. 多点认证wi-fi_准备使用Wi-Fi 6:认证将于2019年第三季度启动
  7. 阿里AI解锁车场景:达摩院技术输出,天猫精灵进驻奔驰、奥迪和沃尔沃
  8. oracle case grouping,ORACLE GROUPING函数的使用
  9. python生产者消费者模式_【整理】Python生产者消费者模型代码 | 勤奋的小青蛙
  10. ImageZoom 图片放大效果
  11. 三维偏序:CDQ分治
  12. pc系统安全问题让你防不胜防--安装系统屏保时,偶然发现没有安装的ie工具栏软件baidu_jpwb(Just Under/WINDOWS)!
  13. 华为重启交换机命令_华为交换机常用命令
  14. crfclust.bdb文件过大处理
  15. 山东大学研究生计算机学院导师,山东大学计算机科学与技术学院研究生导师简介-杨义军...
  16. Python学习日记04
  17. 花椒母公司花房更新招股书:年利润4亿 周鸿祎是大股东
  18. 基于DHT网络的最强BT资源搜索引擎engiy.com
  19. 网页中嵌入外部页面的四种方法
  20. http拨测是什么意思_网络性能拨测-网络传输速度体验检测系统有哪些指标?

热门文章

  1. Transact_SQL小手册
  2. 国家卫健委发布第一版新冠疫苗接种技术指南
  3. 2020全国高中清华北大录取人数榜,各位学生快看!
  4. C++程序设计之函数对象
  5. 对称密码获取(OJ)
  6. socket未读消息 如何设计_如何设计IM系统的消息架构?
  7. java对象比较 hashcode_Java Objects.hash()与自己实现的hashCode()比较
  8. 惠普服务器年销售额,IBM和惠普去年分列服务器收入和发货量第一
  9. jvm 什么是对象头,里面有什么
  10. 009_Redis的事物