- 浏览: 923377 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (229)
- spring (20)
- myBatis (1)
- javase (31)
- 设计模式 (1)
- jQuery EasyUI (4)
- 编程工具 (8)
- Hibernate (3)
- tomcat (3)
- js (27)
- Jboss (2)
- dom4j (1)
- 操作系统 (5)
- 数据库 (26)
- springmvc (6)
- 程序人生 (5)
- JDBC (1)
- android (6)
- groovy (2)
- memcached (11)
- Nginx (8)
- maven (7)
- javaEE (13)
- jquery (3)
- linux (4)
- 单元测试 (6)
- 算法 (6)
- resin 服务器 (5)
- 缓存 (8)
- slf4j日志 (1)
- resin 服务器;log4j (2)
- 性能调休 (25)
- 网络编程 (10)
- 多线程 (9)
- json (1)
最新评论
-
lliiqiang:
主要原因还是因为html格式太复杂多变了。很难过滤所有的危险代 ...
java 防止xss攻击 -
u011670948:
Mustache模板遍历输出数据 -
u011670948:
Mustache模板遍历输出数据 -
masuweng:
spring @Autowire 的注解默认是按类型注入bean -
masuweng:
spring @Autowire 的注解默认是按类型注入bean
转:http://www.blogjava.net/EvanLiu/archive/2008/08/31/224453.html,有删改
工作中碰到个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了
下面是网上的其他解释,更能从本质上解释原因:
当使用 fail-fast iterator 对 Collection 或 Map 进行迭代操作过程中尝试直接修改 Collection /
Map 的内容时,即使是在单线程下运行,ava.util.ConcurrentModificationException 异常也将被抛出。
Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator
被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭
代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出
java.util.ConcurrentModificationException 异常。
所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
有意思的是如果你的 Collection / Map 对象实际只有一个元素的时候,
ConcurrentModificationException 异常并不会被抛出。这也就是为什么在 javadoc 里面指出: it would
be wrong to write a program that depended on this exception for its
correctness: ConcurrentModificationException should be used only to
detect bugs.
解决方案:
1.如果在迭代过程中,需要往Collection 或 Map中插入新的元素时,不要用他们的API提供的方法直接插入删除,可以考虑通过使用他们的迭代器的新增,删除方法来操作元素.
2.不要用迭代器循环,而是直接将Collection 或 Map转换成数组来循环即可.
http://gceclub.sun.com.cn/yuanchuang/week-14/iterator.html
另外,在增强的for循环中,修改集合元素的数量时,也会报java.util.ConcurrentModificationException
如:
import java.util.ArrayList; import java.util.List; public class ListTest { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("Stringfsdf"); list.add("fdsdf"); list.add("lby"); for(String s : list){ if("lby".equalsIgnoreCase(s)){ list.remove(s); } } } }
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at ListTest.main(ListTest.java:15)
原理和上面的一样,我猜的
发表评论
-
并发控制
2016-10-20 16:11 701有时候并发操作太猛了,会对共享资源(DB、或者网络资源)造 ... -
把一个集合按指定大小分组
2016-10-18 17:54 1108public static <T> List&l ... -
DecimalFormat格式化数据
2016-10-09 17:03 824//统一对末尾带0的小数做去除处理,例如:10.00- ... -
[转]Java编码浅析,字符集(注意区分三个概念)
2015-04-16 15:45 831转:http://www.iteye.com/topic/3 ... -
[转]Java clone() 浅克隆与深度克隆
2015-01-12 14:44 880转:http://blog.csdn.net/shootyo ... -
java快速排序
2014-05-27 16:20 772快速排序是对冒泡排序的一种改进。它的基本思想 ... -
ExecutorService的execute和submit方法[转]
2014-05-14 12:30 1230转:http://blog.csdn.net/peachpi ... -
Java线程池使用说明[转]
2014-05-14 12:15 888转:http://automaticthoughts ... -
ExecutorService与Executors例子的简单剖析[转]
2014-05-14 11:14 963转:http://www.cnblogs.com/yezhe ... -
Java并发编程之ConcurrentHashMap[转]
2014-04-28 10:56 889转:http://www.iteye.com/topic/ ... -
使用java.util.BitSet 求素数的算法
2014-01-01 21:48 868转:http://blog.csdn.net/feihong ... -
java中的BitSet学习
2014-01-01 21:44 933转:http://blog.csdn.net/feihong ... -
javaMail发送邮件设置发件人中文昵称
2013-10-16 12:06 2776转:http://blog.csdn.net/mengxi ... -
JDWP了解 与解决 ERROR: JDWP Transport dt_socket failed to initialize, TRANSPORT_INIT(
2013-09-11 09:09 4906转: http://blog.csdn.net/cicada ... -
内部类的参数问题
2013-07-14 09:41 845比如说有一个方法,如下: //参数file要加fin ... -
从File类型得到 byte数组
2013-04-24 16:12 1352public bytes[] getBytesFrom ... -
sleep和wait的区别
2013-03-09 09:54 999转:http://www.cnblogs.com/p ... -
Java Mail发送带有图片的html格式的邮件
2013-01-18 17:55 2689转:http://blog.csdn.net/fr ... -
java的值传递
2012-10-12 11:37 976任何时候传入java方法的参数都是值传递, 如果是基本数据 ... -
int类型与char类型
2012-08-27 11:42 9941转:http://blog.csdn.net/liminwan ...
相关推荐
java.util.ConcurrentModificationException 异常问题详解1
java.util.ConcurrentModificationException 解决方法 在使用iterator.hasNext()操作迭代器的时候,如果此时迭代的对象发生改变,比如插入了新数据,或者有数据被删除。 则使用会报以下异常: Java.util....
主要介绍了出现java.util.ConcurrentModificationException 问题及解决办法的相关资料,需要的朋友可以参考下
Spring数据mongodb测试 在Collections.synchronizedList或Collections.synchronizedSet上测试spring数据mongodb ConcurrentModificationException
java.util.ConcurrentModificationException: mutation occurred during iteration [error] scala.collection.mutable.MutationTracker$.checkMutations(MutationTracker.scala:43) [error] scala.collection....
java中,List在遍历的时候,如果被修改了会抛出java.util.ConcurrentModificationException错误。 看如下代码: import java.util.ArrayList; import java.util.List; public class Resource3 { public ...
Map在遍历时候通常 现获得其键值的集合Set,然后用迭代器Iterator来对Map进行遍历。
简述synchronized和java.util.concurrent.locks.Lock的异同 ? 34.EJB规范规定EJB中禁止的操作有哪些? 35.java除了8种基本类型外,在虚拟机里还有哪一种,有什么作用? 36.除了使用new关键字创建对象意外,试列举...
JAVA相关基础知识 1、面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用...
超级有影响力的Java面试题大全文档 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。...