通过ArrayList对modCount的操作分析fail-fast 机制
AbstractList类中有一个属性
protected transient int modCount = 0;
api中对它的描述是:
- 此列表已被结构修改的次数。 结构修改是改变列表大小的那些修改,或以其他方式扰乱它,使得正在进行的迭代可能产生不正确的结果。
- 该字段由迭代器和列表迭代器实现使用,由
iterator
和listIterator
方法返回。 如果该字段的值意外更改,迭代器(或列表迭代器)将抛出一个ConcurrentModificationException
响应next
,remove
,previous
,set
或add
操作。 这提供了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 机制相关推荐
- Java - Java集合中的快速失败Fail Fast 机制
文章目录 什么是 fail-fast 源码解读 Itr 为什么对集合的结构进行修改会发生并发修改异常-源码分析 修改方法之 remove 修改方法之 add 案例分享 [案例一] [案例二] [案例三 ...
- Fail - Fast机制
平常在使用集合的时候肯定会遇到过遍历删除集合中的某些元素,哪么在进行操作的时候大家有 没有遇到过什么问题呢?最近在使用集合进行遍历删除元素的时候,我就碰到了这个异常:java.util.Concurr ...
- Java - Java集合中的安全失败Fail Safe机制 (CopyOnWriteArrayList)
文章目录 Pre 概述 fail-safe的容器-CopyOnWriteArrayList add remove函数 例子 缺陷 使用场景 Pre Java - Java集合中的快速失败Fail Fa ...
- 【转载】ArrayList 中数据删除 fail fast
2019独角兽企业重金招聘Python工程师标准>>> 本文转载自http://shift-alt-ctrl.iteye.com/blog/1839147 在循环arrayLlist ...
- 什么是Fail Fast和Fail Safe?
这里是目录标题 1. Fail Fast a. 概念 b. 原理 c. 关注点 d. 注意 2. Fail Safe a. 概念 b. 原理 3. Fail Fast 和 Fail Safe的区别 1 ...
- 聊聊hikari与tomcat jdbc pool的fail fast
序 本文主要研究在中途数据库挂的情况下,hikari与tomcat jdbc pool的fail fast情况. 实验代码 @Testpublic void testDatabaseDownAndUp ...
- 【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 ...
- Fail Fast与Fail Safe的区别
Fail Fast Fail Fast Iterator在遍历集合时,若该集合发生了结构性的改变,则将抛出 ConcurrentModification 异常.例如: Map<String, S ...
- Java Review - ArrayList 源码解读
文章目录 概述 方法的执行效率 源码剖析 底层数据结构 -数组 构造函数 自动扩容机制 set() get add()/addAll() remove() trimToSize() indexOf() ...
最新文章
- 聚焦基础科学 引领未来发展
- 自由主义者的周一和周五
- Python Selenium 常用方法总结
- 112. Path Sum 路径总和
- 万字长文深度解析python 单元测试
- 多点认证wi-fi_准备使用Wi-Fi 6:认证将于2019年第三季度启动
- 阿里AI解锁车场景:达摩院技术输出,天猫精灵进驻奔驰、奥迪和沃尔沃
- oracle case grouping,ORACLE GROUPING函数的使用
- python生产者消费者模式_【整理】Python生产者消费者模型代码 | 勤奋的小青蛙
- ImageZoom 图片放大效果
- 三维偏序:CDQ分治
- pc系统安全问题让你防不胜防--安装系统屏保时,偶然发现没有安装的ie工具栏软件baidu_jpwb(Just Under/WINDOWS)!
- 华为重启交换机命令_华为交换机常用命令
- crfclust.bdb文件过大处理
- 山东大学研究生计算机学院导师,山东大学计算机科学与技术学院研究生导师简介-杨义军...
- Python学习日记04
- 花椒母公司花房更新招股书:年利润4亿 周鸿祎是大股东
- 基于DHT网络的最强BT资源搜索引擎engiy.com
- 网页中嵌入外部页面的四种方法
- http拨测是什么意思_网络性能拨测-网络传输速度体验检测系统有哪些指标?
热门文章
- Transact_SQL小手册
- 国家卫健委发布第一版新冠疫苗接种技术指南
- 2020全国高中清华北大录取人数榜,各位学生快看!
- C++程序设计之函数对象
- 对称密码获取(OJ)
- socket未读消息 如何设计_如何设计IM系统的消息架构?
- java对象比较 hashcode_Java Objects.hash()与自己实现的hashCode()比较
- 惠普服务器年销售额,IBM和惠普去年分列服务器收入和发货量第一
- jvm 什么是对象头,里面有什么
- 009_Redis的事物