ConcurrentModificationException 异常
来源:互联网 发布:如何用vlookup匹配数据 编辑:程序博客网 时间:2024/04/30 16:26
源码分析【转】
用iterator遍历集合时要注意的地方:不可以对iterator相关的地方做添加或删除操作。
下面用List为例来说明为什么会报 ConcurrentModificationException 这个异常,其它集合类似可以自己思考。
运行这段代码的结果
大家都知道for(String str : set) 这句话实际上是用到了集合的iterator() 方法
在iterator的时候是产生了一个List的内部类Itr
JDK源码
public Iterator<E> iterator() {
return new Itr();
}
在new Itr()时有一个关键性的操作
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
再回头看一下List 的 remove方法
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++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
}
再看一下 iterator.next()操作
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
相信看到这儿大家已经应该明白了为什么会出现在这个异常了。
总结:
iterator 时 将expectedModCount = modCount 在remove()时 modCount++ 在next()时
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
一旦删除或添加元素后 modCount ,expectedModCount 这两个值就会不一致 当next时就会报ConcurrentModificationException
了解了原由,解决方案就很简单了
在遍历时用一个集合存放要删除的对象 在遍历完后 调用removeAll(Collection<?> c) 就OK了。
------------------------------------------------------------------------------------------------------------------------------
java.util.ConcurrentModificationException 解决办法[转]
今天在项目的中有一个需求,需要在一个Set类型的集合中删除满足条件的对象,这时想当然地想到直接调用Set的remove(Object o)方法将指定的对象删除即可,测试代码:
public class Test {
public static void main(String[] args) {
User user1 = new User();
user1.setId(1);
user1.setName("zhangsan");
User user2 = new User();
user2.setId(2);
user2.setName("lisi");
Set userSet = new HashSet();
userSet.add(user1);
userSet.add(user2);
for (Iterator it = userSet.iterator(); it.hasNext();) {
User user = (User) it.next();
if (user.getId() == 1) {
userSet.remove(user);
}
if (user.getId() == 2) {
user.setName("zhangsan");
}
}
for(Iterator it = userSet.iterator(); it.hasNext(); ) {
User user = (User) it.next();
System.out.println(user.getId() + "=>" + user.getName());
}
}
}
但运行程序的时候,却发现出错了:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$KeyIterator.next(Unknown Source)
at test.Test.main(Test.java:23)
从API中可以看到List等Collection的实现并没有同步化,如果在多线程应用程序中出现同时访问,而且出现修改操作的时候都要求外部操作同步化;调用Iterator操作获得的Iterator对象在多线程修改Set的时候也自动失效,并抛出java.util.ConcurrentModificationException。这种实现机制是fail-fast,对外部的修改并不能提供任何保证。
网上查找的关于Iterator的工作机制。Iterator是工作在一个独立的线程中,并且拥有一个mutex锁,就是说Iterator在工作的时候,是不允许被迭代的对象被改变的。Iterator被创建的时候,建立了一个内存索引表(单链表),这个索引表指向原来的对象,当原来的对象数量改变的时候,这个索引表的内容没有同步改变,所以当索引指针往下移动的时候,便找不到要迭代的对象,于是产生错误。List、Set等是动态的,可变对象数量的数据结构,但是Iterator则是单向不可变,只能顺序读取,不能逆序操作的数据结构,当Iterator指向的原始数据发生变化时,Iterator自己就迷失了方向。
如何才能满足需求呢,需要再定义一个List,用来保存需要删除的对象:
List delList = new ArrayList();
最后只需要调用集合的removeAll(Collection con)方法就可以了。
public class Test {
public static void main(String[] args) {
boolean flag = false;
User user1 = new User();
user1.setId(1);
user1.setName("shangsan");
User user2 = new User();
user2.setId(2);
user2.setName("lisi");
Set userSet = new HashSet();
userSet.add(user1);
userSet.add(user2);
List delList = new ArrayList();
for (Iterator it = userSet.iterator(); it.hasNext();) {
User user = (User) it.next();
if (user.getId() == 1) {
delList.add(user);
}
if (user.getId() == 2) {
user.setName("zhangsan");
}
}
userSet.removeAll(delList);
for(Iterator it = userSet.iterator(); it.hasNext(); ) {
User user = (User) it.next();
System.out.println(user.getId() + "=>" + user.getName());
}
}
}
ps:
楼主的解决方法不够好,下面是网上找的高人的解决之道。
1.对于HashMap,可有用ConcurrentHashMap来代替解决并发的问题
2.对于非HashMap,如ArrayList等,用Iterator来查看数据,然后用Iterator自带的remove方法来实现安全删除
------------------------------------------------------------------------------------------------------------------------------
ava.util.ConcurrentModificationException异常网上机以找到很多资料。整体上看了一下,基本上都是说那些原理的,比较啰嗦,我只简单说明一下原理和解决方案,用来备忘
原理:由于在迭代的过程中对集体进行了增加或者删除,导致索引西匹配不上而报异常
解决方案:
1.对于HashMap,可有用ConcurrentHashMap来代替解决并发的问题
2.对于非HashMap,如ArrayList等,用Iterator来查看数据,然后用Iterator自带的remove方法来实现安全删除
代码如下
- ConcurrentModificationException 异常
- ConcurrentModificationException 异常
- ConcurrentModificationException 异常
- ConcurrentModificationException异常
- ConcurrentModificationException异常
- concurrentmodificationexception异常
- ConcurrentModificationException异常
- ConcurrentModificationException异常
- 异常ConcurrentModificationException
- 异常:java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException异常
- java.util.ConcurrentModificationException异常
- ConcurrentModificationException 的异常分析
- java.util.ConcurrentModificationException 异常
- ConcurrentModificationException 的异常分析
- 异常:java.util.ConcurrentModificationException
- 异常:java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException 异常
- 为何感到空虚无干劲
- 什么是默认网关
- 什么是网关
- 新手第一课:fopen(), fclose()和segmentation fault(Linux 权限问题)
- JSTL详解(二)
- ConcurrentModificationException 异常
- Jupiter Code Review Reference -- Jupiter代码审查工具使用参考 (修改版)
- spring tx:advice 和 aop:config 配置事务
- lucene的demo环境搭建
- 用System.currentTimeMillis()计算程序运行花费的时间
- CalendarExtender日历中文本地化支持
- 利用Tomcat7.0新特性,用BS实现CS的聊天服务器
- address
- 嗯,我也有技术博客了。