我的观点
fail-fast是什么就不多解释了,应该注意到的是(以ArrayList为例):modCount位于AbstractList中,

protected transient int modCount = 0;

并无volatile修饰,因此当两线程是共用同一个cpu时才会抛出并发修改异常。比如:

线程1正在用迭代器来读,此时共用同一个cpu**的线程2来修改list,使得modCount++。由于共用同一个cpu,那么所修改的是**同一个缓存中的modCount,这样使得线程1下一次检查时发现与期望值不等,便会抛出异常

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

但是如果线程2用的是不同的cpu,而modCount又没有volatile修饰,那么线程2对modCount的修改不知道什么时候才会写回主存,也不知道什么时候线程1才会重新从主存中读取modCount。
因此出现并发修改也不一定会抛异常,而其实只要违反规则,单线程照样会抛出并发修改异常

public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
Iterator iterator=list.iterator();
while(iterator.hasNext()){
iterator.next();
list.add(3);
}
}
// Exception in thread "main" java.util.ConcurrentModificationException
// at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
// at java.util.ArrayList$Itr.next(ArrayList.java:859)
// at github.com.AllenDuke.concurrentTest.future.FutureTest.main(FutureTest.java:29)

但是线程用哪个cpu执行任务是不可知的。

所见的网上的答案
注意:这里异常的抛出条件是检测到modCount != expectedModCount这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedModCount值,则异常不会抛出。因此,不能依赖于这个异常是否抛出而进行并发操作的变成,这个异常只建议用于检测并发修改的bug。

这句话会误让人以为,线程进去修改的时候+1,修改完就-1。但实际上modCount是只会递增的,至少在jdk1.8中没有发现modCount--或是--modCount。利用反射可以看出并不是退出方法就-1,如下:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
ArrayList<Integer> list = new ArrayList<>();
Class c= AbstractList.class;
Field modCountField = c.getDeclaredField("modCount");
modCountField.setAccessible(true);
for (int i = 0; i < 5; i++) {
list.add(i);
System.out.println(modCountField.get(list));
}
}
// 1
// 2
// 3
// 4
//

或者这句话的意思是两个线程同时+1,这样的话,根本原因就和我的观点一致了。

解释为什么不能依赖fail-fast的更多相关文章

  1. 快速失败(fail—fast)和 安全失败(fail—safe)

    快速失败(fail-fast) 在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的结构进行了修改(增加.删除),则会抛出Concurrent Modification Exception. 原理 ...

  2. Fail Fast and Fail Safe Iterators in Java

    https://www.geeksforgeeks.org/fail-fast-fail-safe-iterators-java/ Fail Fast and Fail Safe Iterators ...

  3. Spring IOC源代码具体解释之容器依赖注入

    Spring IOC源代码具体解释之容器依赖注入 上一篇博客中介绍了IOC容器的初始化.通过源代码分析大致了解了IOC容器初始化的一些知识.先简单回想下上篇的内容 加载bean定义文件的过程.这个过程 ...

  4. fail fast和fail safe策略

    优先考虑出现异常的场景,当程序出现异常的时候,直接抛出异常,随后程序终止 import java.util.ArrayList; import java.util.Collections; impor ...

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

    这是我遇到的问题 Could not locate PropertySource and the fail fast property is set, failing springcloud的其他服务 ...

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

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

  7. Java Gradle入门指南之依赖管理(添加依赖、仓库、版本冲突)

        开发任何软件,如何管理依赖是一道绕不过去的坎,软件开发过程中,我们往往会使用这样那样的第三方库,这个时候,一个好的依赖管理就显得尤为重要了.作为一个自动构建工作,Gradle对依赖管理有着很好 ...

  8. 简单解析依赖注入(控制反转)在Spring中的应用

    IoC——Inversion of Control  控制反转DI——Dependency Injection   依赖注入 大家都知道,依赖注入是Spring中非常重要的一种设计模式.可能很多初学者 ...

  9. AngularJS(15)-依赖注入

    AngularJS 依赖注入 什么是依赖注入 wiki 上的解释是:依赖注入(Dependency Injection,简称DI)是一种软件设计模式,在这种模式下,一个或更多的依赖(或服务)被注入(或 ...

随机推荐

  1. pqsql 防注入

    在数据库查询时经常会遇到根据传入的参数查询内容的情况,传入的参数有可能会带有恶意代码,比如or 1=1,这样where判断为true,就会返还所有的记录.为了解决这个问题,可以在参数外面包一层单引号, ...

  2. express项目创建

    npm install express-generator -g       全局安装express生成器 express -h  帮助中心 express 项目名 npm i    安装依赖 nod ...

  3. 【LC_Lesson4】---罗马数字到整数得转换

    罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000例如, 罗马数字 2 写做 II ,即为两个并列 ...

  4. 树形dp - 求树的直径

    随着杭州西湖的知名度的进一步提升,园林规划专家湫湫希望设计出一条新的经典观光线路,根据老板马小腾的指示,新的风景线最好能建成环形,如果没有条件建成环形,那就建的越长越好. 现在已经勘探确定了n个位置可 ...

  5. postgresql gin索引使用

    由于属于老项目,postgresql使用版本9.6,主要解决‘%name%"查询无法使用索引问题.pg_trgm模块提供函数和操作符测定字母,数字,文本基于三元模型匹配的相似性, 还有支持快 ...

  6. 使用RobotFramework的JavaRemoteLibrary

    终于被迫使用了Java的远程接口库(为了同时使用Java和python的用例库,且为了在pybot下跑速度能快一些),路途比实际想的要坎坷,记录下来. 远程库的原理在前边一篇文章中记录过: http: ...

  7. 在winform中使用cefsharp.winform嵌入浏览器(含视频教程)

    免费视频教程和源码: https://www.bilibili.com/video/av84573813/ 1. 开始使用CefSharp在Winform中嵌入网页 2. 解决重复打开Cefsharp ...

  8. 关于checkbox取值的问题

    今天,在做一个小界面的时候,要用到checkbox来判断用户是否选择记住密码. 本来我想这个不是挺简单吗,直接用jquery获取checkbox的checked属性值好了,如下: var rememb ...

  9. 【模板】2-SAT问题

    问题简述 有 \(n\) 个变量,每个变量可赋为 \(1\) 或 \(0\) 必须满足一些限制条件,如" \(a\) 为1 或 \(b\) 为0 " " \(a\) 为0 ...

  10. Java服务端两个常见的并发错误

    理想情况来讲,开发在开始编写代码之前就应该讲并发情况考虑进去,但是大多数实际情况确是,开发压根不会考虑高并发情况下的业务问题.主要原因还是因为业务极难遇到高并发的情况. 下面列举两个比较常见的后端编码 ...