我的观点
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. spring boot通过@Bean注解定义一个Controller

    功能需求 提供一个公共的jar包给其他业务模块依赖,需要在这个公共的jar中暴露一个restful API 采用spring auto config机制,在公共jar包中定义spring.factor ...

  2. Spring Boot 2.X(十九):集成 mybatis-plus 高效开发

    前言 之前介绍了 SpringBoot 整合 Mybatis 实现数据库的增删改查操作,分别给出了 xml 和注解两种实现 mapper 接口的方式:虽然注解方式干掉了 xml 文件,但是使用起来并不 ...

  3. vue+bootstrap4+mybatis分页

    先看效果 Springboot+Mybatis+Pagehelper分页具体实现略. Controller返回数据 @GetMapping("/findByPage") publi ...

  4. java jdk9的特性 jshell

    1.进入 jshell 2.推出 /exit() 和python的解释器用法差不多

  5. Flask DBUtils

    作用:创建连接池,解决多线程问题 1.安装模块 pip3 install -i https://pypi.douban.com/simple DBUtils 2.settings.py(配置文件) f ...

  6. Java入门 - 高级教程 - 06.邮件收发

    原文地址:http://www.work100.net/training/java-email.html 更多教程:光束云 - 免费课程 邮件收发 序号 文内章节 视频 1 概述 2 发送一封简单的邮 ...

  7. json的结构和表示方式(对象object、数组array)

    json简单说就是javascript中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结构可以表示各种复杂的结构 1.对象:对象在js中表示为“{}”括起来的内容,数据结构为 {key ...

  8. 通过识别页面内容获得返回值判断后续执行(exists指令的用法)

    本案例主要用到airtest 的exists指令 从指令解释可以知道,当判断某图片不存在的时候,会返回false值 脚本思路即为如果返回值==false则执行A,!=fales则执行B 下图脚本思路, ...

  9. python HelloWorld 的 4 种姿势,你知道几种

    安装完 Python 之后该干啥,当然是要 say HelloWorld 了. python.exe 就是个普通程序 和其它所有命令一样,在命令行中敲下 python 并回车的时候,操作系统去 PAT ...

  10. Java 添加、读取、删除Excel形状

    本文介绍通过java程序在excel中操作形状(图形)的方法,包括: 1. 添加形状(如设置形状类型/位置/大小.形状颜色填充(单色/渐变色/纹理/图片填充).形状显示或隐藏.形状倾斜角度.添加文本到 ...