ConcurrentModificationException 详解
工作中碰到个ConcurrentModificationException。代码如下:
List list = ...;
for(Iterator iter = list.iterator(); iter.hasNext();) {
Object obj = iter.next();
...
if(***) {
list.remove(obj);
}
}
在执行了remove方法之后,再去执行循环,iter.next()的时候,报java.util.ConcurrentModificationException(当然,如果remove的是最后一条,就不会再去执行next()操作了)
下面来看一下源码
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
public interface Collection<E> extends Iterable<E> {
...
Iterator<E> iterator();
boolean add(E o);
boolean remove(Object o);
...
}
这里有两个remove方法
接下来来看看AbstractList
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
//AbstractCollection和List都继承了Collection
protected transient int modCount = 0;
private class Itr implements Iterator<E> { //内部类Itr
int cursor = 0;
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification(); //特别注意这个方法
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet); //执行remove对象的操作
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount; //重新设置了expectedModCount的值,避免了ConcurrentModificationException的产生
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount) //当expectedModCount和modCount不相等时,就抛出ConcurrentModificationException
throw new ConcurrentModificationException();
}
}
}
remove(Object o)在ArrayList中实现如下:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++; //只增加了modCount
....
}
所以,产生ConcurrentModificationException的原因就是:
执行remove(Object o)方法之后,modCount和expectedModCount不相等了。然后当代码执行到next()方法时,判断了checkForComodification(),发现两个数值不等,就抛出了该Exception。
要避免这个Exception,就应该使用remove()方法。
这里我们就不看add(Object o)方法了,也是同样的原因,但没有对应的add()方法。一般嘛,就另建一个List了
下面是网上的其他解释,更能从本质上解释原因:
Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
好文:http://www.cnblogs.com/skywang12345/p/3308762.html
ConcurrentModificationException 详解的更多相关文章
- java.util.ConcurrentModificationException详解
引用于http://blog.csdn.net/dabing69221/article/details/40065071 在使用set/map时,一个可爱的小bug:Java.util.Concurr ...
- 迭代器Iterator与ConcurrentModificationException详解
背景:一直以来对迭代器的问题理解不是很透彻,特别是迭代器和异常ConcurrentModificationException之间的联系.通过debug,详细了解其底层的具体实现过程. 简介 Itera ...
- java的集合框架最全详解
java的集合框架最全详解(图) 前言:数据结构对程序设计有着深远的影响,在面向过程的C语言中,数据库结构用struct来描述,而在面向对象的编程中,数据结构是用类来描述的,并且包含有对该数据结构操作 ...
- 转:Java HashMap实现详解
Java HashMap实现详解 转:http://beyond99.blog.51cto.com/1469451/429789 1. HashMap概述: HashMap是基于哈希表的M ...
- 【转】java list用法示例详解
转自:http://www.jb51.net/article/45660.htm java中可变数组的原理就是不断的创建新的数组,将原数组加到新的数组中,下文对java list用法做了详解. Lis ...
- Java SE之快速失败(Fast-Fail)与快速安全(Fast-Safe)的区别[集合与多线程/增强For](彻底详解)
声明 特点:基于JDK源码进行分析. 研究费时费力,如需转载或摘要,请显著处注明出处,以尊重劳动研究成果:博客园 - https://www.cnblogs.com/johnnyzen/p/10547 ...
- Java集合详解8:Java的集合类细节精讲
Java集合详解8:Java集合类细节精讲 今天我们来探索一下Java集合类中的一些技术细节.主要是对一些比较容易被遗漏和误解的知识点做一些讲解和补充.可能不全面,还请谅解. 本文参考:http:// ...
- Java集合详解3:Iterator,fail-fast机制与比较器
Java集合详解3:Iterator,fail-fast机制与比较器 今天我们来探索一下LIterator,fail-fast机制与比较器的源码. 具体代码在我的GitHub中可以找到 https:/ ...
- java集合类之LinkedList详解
一.LinkedList简介 由于LinkedList是一个实现了Deque的双端队列,所以LinkedList既可以当做Queue,又可以当做Stack,在将LinkedList当做Stack时,使 ...
随机推荐
- C#/.NET 学习之路——从入门到放弃
原文链接地址:http://blog.liuhaoyang.me/dotnet/2016/11/25/csharp-books/ 向架构师大步迈进的书单 C# 入门 <C# 本质论> &l ...
- android将应用中图片保存到系统相册并显示
我应用到的场景是程序中在视频通讯时截图,将截图保存到本地相册中 /*** @param bmp 获取的bitmap数据 * @param picName 自定义的图片名*/ public static ...
- Java虚拟机(JVM)体系结构概述及各种性能参数优化总结
转自:http://blog.csdn.net/zhongwen7710/article/details/39213377 第一部分:相关的概念 数据类型 Java虚拟机中,数据类型可以分为两类:基本 ...
- HBase二级索引与Join
转自:http://www.oschina.net/question/12_32573 二级索引与索引Join是Online业务系统要求存储引擎提供的基本特性.RDBMS支持得比较好,NOSQL阵营也 ...
- OSPF的特征、术语、包类型、邻居关系的建立、RID的选择、DR和BDR的选举、度量值的计算、默认路由、验证
链路状态路由协议OSPF的特征.术语.包类型.邻居关系的建立.RID的选择.DR和BDR的选举.度量值的计算.默认路由.验证等. 文章目录 [*1*].链路状态路由协议概述 工作过程 优缺点 [*2* ...
- TI webench 一款不错的软件
之前在一些电子论坛的网站看到过关于TI webench的介绍,今天适用了一下,确实功能很强大,设计内容可以输入你所要设计的内容,包括下面内容: 下图是笔者设计的一个FPGA供电系统,采用5V输入, ...
- 关于Unity中关节的使用(一)
1: 刚体的形状大小在物理世界里面是不变的,可是很多时候,我们需要多个刚体来配合使用;2: 关节: 连接刚体与刚体的对应的物理模拟;3: 关节类型: 铰链关节,弹簧关节, 固定关节, 角色关节,可配置 ...
- Pandas 的轴向连接 concat
在pandas里面,另一种数据何必运算也被称为连接(concatenation).绑定(binding)或堆叠(stacking). Numpy的轴向连接, concatenation Numpy有一 ...
- 第三百四十节,Python分布式爬虫打造搜索引擎Scrapy精讲—css选择器
第三百四十节,Python分布式爬虫打造搜索引擎Scrapy精讲—css选择器 css选择器 1. 2. 3. ::attr()获取元素属性,css选择器 ::text获取标签文本 举例: extr ...
- Lemon OA第4篇:常用功能
OA,Office Automation的简写,中文意思办公自动化,不同的人有不同的见解,可以简单的理解为网络化办公,高效.协同是其显著的特点,如今正在朝着智能的方向发展 平时不擅长文字,写出来几句话 ...