ConcurrentModificationException(并发修改异常)的分析
1)介绍
并发修改ConcurrentModificationException错误是开发中一个常见错误,多发生在对一个Collection边遍历边做影响size变化的操作中,下面以ArrayList为例分析ConcurrentModificationException错误。
2)分析
ArrayList初始数据如下:
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
【场景1】不会有并发修改错误
int length = list.size();
for (int i = 0; i < length; i++) {
if (list.get(i).equals(2)) {
list.add(10);
}
}
【场景2】会有并发修改错误
for(int temp : list) {
if(temp == 2) {
list.add(10);
}
}
【场景3】会有并发修改错误
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()) {
if(iterator.next().equals(2)) {
list.add(10);
}
}
【场景4】没有并发修改问题
ListIterator<Integer> listIterator = list.listIterator();
while (listIterator.hasNext()) {
if (listIterator.next().equals(2)) {
listIterator.add(10);
}
}
【分析】
其实ConcurrentModificationException异常的抛出是由于checkForComodification(AbstractList类中)方法的调用引起的。
private void checkForComodification() {
if (this.modCount != l.modCount)
throw new ConcurrentModificationException();
}
而checkForComodification方法的调用发生在Iterator相关api方法中,在调用list的iterator方法会创建一个Itr对象。

在创建会与AbstractList的modCount赋予相同的值, 而在Itr的next方法中会调用checkForComodification

在场景3中,list.add操作更改modCount的值,所以会有并发修改错误,而场景1中并没有使用iterator相关api,add操作虽然修改了modCount但是不会检查modCount所以没有并发修改错误。
场景4中,ListItr类add方法
public void add(E e) {
checkForComodification();
try {
int i = cursor;
ArrayList.this.add(i, e);
cursor = i + 1;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
其中8行:在调用了list.add操作之后,将ListItr中的expectedModCount与AbstractList中的modCount进行了同步,所以在下次调用next也就不会抛出异常了,此时假如以后不调用next或者又重新创建了 ListItr也不会有异常抛出。
最后场景2并没有使用Iterator中的api为什么也抛出了异常了。其实编译器会将for-each循环代码编译为Iterator相关api的调用。为了便于查看编译后的代码这里添加一个“———-”打印。
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
System.out.println("------------");
for (int temp : list) {
if (temp == 2) {
list.add(10);
}
}
编译后的字节码为:

所以场景2和场景3是一样的,也会抛出异常了。
ConcurrentModificationException(并发修改异常)的分析的更多相关文章
- ConcurrentModificationException并发修改异常
//创建集合对象 Collection c = new ArrayList(); c.add("hello"); c.add("world"); c.add(& ...
- 【Java笔记】以并发修改异常为例总结的出错解决办法
先来看出错代码: /*需求: 遍历已有集合 如果在集合中发现存在字符串元素"world" 则在"world"后添加元素"javaee" */ ...
- 集合并发修改异常-foreach的时候不可修改值
直接上代码: 无意间发现的://这个方法本身是为后面的集合去掉前面集合的重复数据一直报错,并发修改异常,仔细看mainList正在迭代循环,然后我进行了remove操作,这个时候就会报这个错.故:总结 ...
- 29.2 Iterator 迭代器ConcurrentModificationException:并发修改异常处理
/** Iterator:迭代器* * 需求:判断集合中是否包含元素java,如果有则添加元素android * Exception in thread "main" java.u ...
- List集合遍历时修改元素出现并发修改异常总结
什么是并发修改异常: 当我们在遍历实现了collection接口与iterator接口的集合时(List.Set.Map), 我们可以通过遍历索引也可以通过迭代器进行遍历.在我们使用迭代器进行遍历集合 ...
- 大杂烩 -- Iterator 并发修改异常ConcurrentModificationException
基础大杂烩 -- 目录 大杂烩 -- Java中Iterator的fast-fail分析 大杂烩 -- Iterator 和 Iterable 区别和联系 问题: 在集合中,判断里面有没有" ...
- 集合框架之——迭代器并发修改异常ConcurrentModificationException
问题: 我有一个集合,如下,请问,我想判断里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现. 使用普通迭代器出现的异常: ...
- ConcurrentModificationException(并发修改异常)的解决
[异常解释] ConcurrentModificationException:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常.[产生的原因] 迭代器是依赖于集合而存在的,在判断成功后,集合 ...
- 理解和解决Java并发修改异常ConcurrentModificationException(转载)
原文地址:https://www.jianshu.com/p/f3f6b12330c1 理解和解决Java并发修改异常ConcurrentModificationException 不知读者在Java ...
- 并发修改异常(ConcurrentModificationException)
并发修改异常(ConcurrentModificationException) 这个异常,使用集合的时候应该很常见,这个异常产生的原因是因为java中不允许直接修改集合的结构. 先贴上个有趣的例子,给 ...
随机推荐
- windows IDEA注册码激活方法(2018.4.8)靠谱可用!
简介 intellij idea 2018注册码是针对intellij idea 2018软件研发推出,它的使用需要和激活补丁一起使用,安装包里面也拥有破解补丁, 所有无需在进行单独的下载:不过如果选 ...
- Confluence 6 配置草稿保存的时间
这个设置仅仅应用到 Confluence 6.0 及后续版本中,如果你选择 禁用(disable )collaborative editing. 当协同编辑被启用后,我们将会保存所有的修改. 当协同编 ...
- Confluence 6 白名单表达式类型
表达式类型 当添加一个 URL 到白名单列表中的时候,你可以选择采取下面的表达式进行添加. 域名名称(Domain name) 允许 URL 为一个指定的域名. http://www.example. ...
- (六)STL仿函数functor
1.仿函数为算法服务,特点是重载操作符() 2.一共分为3大类,包括算术类,逻辑运算类,相对关系(比较大小):都继承了binary_function 3.仿函数的一些调用示例,其中右边的仿函数没有继承 ...
- Java的家庭记账本程序(A)
日期:2019.2.1 博客期:028 星期五 其实我早就开始开发“家庭记账本”的软件了,只不过写博客写的有点晚,我是打算先做web的!因为Android Studio的教程,还是要对应版本,好多问题 ...
- Linux磁盘与文件系统管理笔记
### Linux磁盘与文件系统管理 linux 最传统的文件系统格式是EXT2,centos7 默认文件系统是xfs(日志式文件系统) 磁盘的组成: 盘片 机械手臂 主轴马达 (机械硬盘) 磁盘格式 ...
- Java 并发类
java.util.concurrent包里 提供了一批线程安全的类 一. java.util.concurrent.atomic java.util.concurrent.atomic包里的原子处理 ...
- hdu4612 卡cin e-DCC缩点
/* 给定无向图,求加入一条边后最少剩下多少桥 */ #include<bits/stdc++.h> using namespace std; #define maxn 200005 #d ...
- cf219d 基础换根法
/*树形dp换根法*/ #include<bits/stdc++.h> using namespace std; #define maxn 200005 ]; int root,n,s,t ...
- jenkins默认会存放目录
jenkins默认会存放在用户主目录下的.jenkins文件夹中 如:Linux root用户:/root/.jenkins 注意:这是linux版本的.windows系统请自行更改.这个值在Jenk ...