解释为什么不能依赖fail-fast
2024-10-04 03:38:09
我的观点
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,这样的话,根本原因就和我的观点一致了。
最新文章
- 使用bootstrap tooltip控件动态修改提示内容
- JavaScript之毒瘤
- JMS的可靠性
- 破解Mysql数据库密码
- 陈朱兴-js写法【案例】:
- Java public, private, protected and default
- 【protobuf进阶】通过.proto文件导出C#支持的.cs类文件
- JavaScript 客户端JavaScript之 Web浏览器的环境
- window环境下安装 pip 工具 【pip为Python的扩展管理工具】
- Python-老男孩-02_装饰器_面向对象_封装_继承_异常_接口_数据库
- Oracle11g静默安装
- python1数据链接总结
- 纯css3打造瀑布流布局
- [笔试题目]使用Stringbuffer无 参的构造函数创建 一个对象时,默认的初始容量是多少? 如果长度不够使用了,自动增长多少倍?
- MiniGUI 如何显示繁体字
- JavaScript-创建日志调试对象(面向对象实例)
- D. The Beatles
- jquery 全选、反选、获取值、背景行、隔行变色和鼠标略过变色变色全特效
- js实现复选框的全选、全不选和反选
- BZOJ1319Sgu261Discrete Roots——BSGS+exgcd+原根与指标+欧拉定理
热门文章
- JSP九大内置对象之session以及eclispe如何关联源码
- js最简单的编写地点
- es5和es6中查找数组中的元素
- STM32F429的特点
- DFS——深度优先搜索的一般格式
- FWT 入门
- python的logging模块使用方法
- 毒瘤养成记1: 如何卡hash
- Java入门 - 语言基础 - 01.Java简介
- Android studio 报错Error:Internal error: (java.lang.ClassNotFoundException) com.google.wireless.android.sdk.stats.IntellijIndexingStats$Index