从 modCount 看 java集合 fail-fast 机制
一、背景
在常见的Java的非线程安全集合类中(如HashMap、ArrayList),经常可以在一些修改结构的操作(如Add)中看到实例变量 modCount++
,来统计集合的修改次数。
从注释也可以看出,该字段是为 fail-fast(快速失败)机制服务。
二、简介
fail-fast 机制是能立刻报告任何可能导致失败的错误检测机制。
在java集合框架中表现为:当构建迭代器时,起初expectedModCount = modCount
,当修改了该集合时,则该集合modCount++
,随后迭代器在迭代下个元素时,会发现当前的modCount
值与期望值expectedModCount
不符,便会抛出ConcurrentModificationException
异常,以避免数据不同步带来的麻烦。
注:
- 使用迭代器的remove()方法不会抛出异常,看源码可知在其中重新设置expectedModCount。
- 该机制不保证存在非同步并发修改时一定会抛出异常,只是尽最大努力去抛出该异常,因此最好不要依赖于该异常去写程序,而只是用于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 机制的更多相关文章
- 从源码看Java集合之ArrayList
Java集合之ArrayList - 吃透增删查改 从源码看初始化以及增删查改,学习ArrayList. 先来看下ArrayList定义的几个属性: private static final int ...
- Java fail-fast 与 fail-safe 机制对比
关于fail-fast参考这篇文章: 从 modCount 看 java集合 fail-fast 机制 一.fail-safe概述以及与fail-fast区别 首先 fail-safe 并不属于J ...
- Java集合框架——容器的快速报错机制 fail-fast 是什么?
前言:最近看 java 集合方面的源码,了解到集合使用了 fail-fast 的机制,这里就记录一下这个机制是什么,有什么用,如何实现的. 一.fail-fast 简介 fail-fast 机制,即快 ...
- Java集合框架中的元素
之前有一篇笔记,讲的是集合和泛型,这几天看Java集合中几个接口的文档,思绪非常混乱,直到看到Oracle的“The Collections Framwork”的页面,条理才清晰些,现在进行整理. 一 ...
- Java集合框架中的快速失败(fail—fast)机制
fail-fast机制,即快速失败机制,是java集合框架中的一种错误检测机制.多线程下用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加.删除),则会抛出Concurre ...
- Java 集合 fail-fast机制 [ 转载 ]
Java 集合 fail-fast机制 [转载] @author chenssy 摘要:fail-fast产生原因.解决办法 在JDK的Collection中我们时常会看到类似于这样的话: 例如,Ar ...
- Java集合详解3:Iterator,fail-fast机制与比较器
Java集合详解3:Iterator,fail-fast机制与比较器 今天我们来探索一下LIterator,fail-fast机制与比较器的源码. 具体代码在我的GitHub中可以找到 https:/ ...
- Java集合详解3:一文读懂Iterator,fail-fast机制与比较器
<Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...
- Java集合最全解析,学集合,看这篇就够用了!!!
在看集合类之前, 我们要先明白一下概念: 1.数据结构 (1):线性表 [1]:顺序存储结构(也叫顺序表) 一个线性表是n个具有相同特性的数据元素的有限序列.数据元素是一个抽象的符号,其具体含义在不同 ...
随机推荐
- 洛谷 P3038 [USACO11DEC]牧草种植Grass Planting
题目描述 Farmer John has N barren pastures (2 <= N <= 100,000) connected by N-1 bidirectional road ...
- 腾讯AI开放平台的接口调用指南
最近无意发现腾讯AI开放平台上提供了大量好玩的人工智能云服务,而且是完全免费的.只需要用QQ号登录即可.这么好的东西,作为一个程序员,当然要试试了! 从上图可以看出腾讯AI开放平台提供的人工智能服务主 ...
- HttpClient 接口调用
String url = "http://127.0.0.1:8080/api"; //然后根据表名获取公司信息 HttpPost httppost = new HttpPost( ...
- 7 SQL 集合运算
7 集合运算 7-1 表的加减法 本章将会和大家一起学习“集合运算”操作.在数学领域,“集合”表示“(各种各样的)事物的总和”:在数据库领域,表示“记录的集合”.具体来说,表.视图和查询的执行结果都是 ...
- openwrt procd分析
procd源码中有很多个main入口,有点懵,不知道procd之外的其他程序是干嘛的.先找资料大概了解了一下procd是什么,然后是守护进程,再然后是openwrt启动流程等等. openwrt启动流 ...
- 数据结构( Pyhon 语言描述 ) — — 第4章:数据和链表结构
数据结构是表示一个集合中包含的数据的一个对象 数组数据结构 数组是一个数据结构 支持按照位置对某一项的随机访问,且这种访问的时间是常数 在创建数组时,给定了用于存储数据的位置的一个数目,并且数组的长度 ...
- 杭电 2141 Can you find it? (二分法)
Description Give you three sequences of numbers A, B, C, then we give you a number X. Now you need t ...
- MySQL 慢查询优化
为什么查询速度会慢 1.慢是指一个查询的响应时间长.一个查询的过程: 客户端发送一条查询给服务器 服务器端先检查查询缓存,如果命中了缓存,则立可返回存储在缓存中的结果.否则进入下一个阶段 服务器端进行 ...
- 理解js的几个关键问题(1):全局变量new和关于hasOwnPropery和PropertyIsEnumerable 等
一.作用域和全局变量 var test=function(){ var a=1; setTimeout(function(){ console.log(a); a=2; },1000); a=3; s ...
- zoj 2736 Daffodil number
Daffodil number Time Limit: 2 Seconds Memory Limit: 65536 KB The daffodil number is one of the ...