java.util.ConcurrentModificationException解决方案

在做一个hibernate+struts的小模块中有一个需求,需要在一个Set类型的集合中删除满足条件的对象,于是想当然地想到直接调用Set的remove(Object o)方法将指定的对象删除即可,但是出现了并发修改的异常,这使得我想起了list的集合中曾经也犯过这个错误。于是到网上查了点资料,自己也模拟了一下错误的出现,在此就总结一下,以便后期再次犯错。


【模拟错误再现:】

package com.jjyy.set.exception;

import java.util.HashSet;
import java.util.Set;

/**
* 模拟Set集合的并发修改错误
* @author Administrator--jiangyu--2014-9-4 上午10:38:32
*
*/
public class ConCurExcepDemo01 {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
set.add("jjyy");
set.add("xzl");
set.add("xpx");
set.add("zcc");
set.add("zzf");
set.add("zgw");
set.add("wjf");
set.add("gw");

for (String str : set) {
if (str.equals("gw")) {
set.remove(str);// 遍历和删除操作 出现并发修改错误
}
}
}
}

运行程序:出现异常
【异常描述:】
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
at java.util.HashMap$KeyIterator.next(HashMap.java:828)
at com.jjyy.set.exception.ConCurExcepDemo.main(ConCurExcepDemo.java:23)



从API中可以看到List等Collection的实现并没有同步化,如果在多 线程应用程序中出现同时访问,而且出现修改操作的时候都要求外部操作同步化;调用Iterator操作获得的Iterator对象在多线程修改Set的时 候也自动失效,并抛出java.util.ConcurrentModificationException。这种实现机制是fail-fast,对外部 的修改并不能提供任何保证。

网上查找的关于Iterator的工作机制。Iterator是工作在一个独立的线程中,并且拥有一个 mutex锁,就是说Iterator在工作的时候,是不允许被迭代的对象被改变的。Iterator被创建的时候,建立了一个内存索引表(单链表),这 个索引表指向原来的对象,当原来的对象数量改变的时候,这个索引表的内容没有同步改变,所以当索引指针往下移动的时候,便找不到要迭代的对象,于是产生错 误。List、Set等是动态的,可变对象数量的数据结构,但是Iterator则是单向不可变,只能顺序读取,不能逆序操作的数据结构,当 Iterator指向的原始数据发生变化时,Iterator自己就迷失了方向。

【代码实例:】
但是怎样才能满足呢?其实很简单,只要再定义一个List或其他的容器,用来保存需要删除的对象,然后调用集合类的removeAll方法即可。
贴出代码:

package com.jjyy.set.exception;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* 模拟Set集合的并发修改错误
* @author Administrator--jiangyu--2014-9-4 上午10:38:32
* 解决方案:
* 可以再定义一个容器来存放要删除的元素 然后只需要调用集合的removeAll(Collection con)方法就可以了。
*/
public class ConCurExcepDemo02 {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
//模拟数据
set.add("jjyy");
set.add("xzl");
set.add("xpx");
set.add("zcc");
set.add("zzf");
set.add("zgw");
set.add("wjf");
set.add("gw2");
set.add("wl2");
set.add("yq2");
//删除前的元素
for (String string : set) {
System.out.print(string + " |");
}
System.out.println();
System.out.println("===================================================");
//定义一个List容器 用于存放要删除的元素
List<String> list = new ArrayList<String>();
for (String str : set) {
if (str.contains("2")) {
list.add(str);
//set.remove(str);
}
}
set.removeAll(list);

//删除后的元素
for (String string : set) {
System.out.print(string + " |");
}
}
}

运行结果:

zgw |xpx |wjf |jjyy |wl2 |zzf |gw2 |yq2 |zcc |xzl |
===================================================
zgw |xpx |wjf |jjyy |zzf |zcc |xzl |





引用\[1\]中提到了一个异常:java.util.ConcurrentModificationException。这个异常通常在多线程环境下出现,当一个线程正在遍历或修改一个集合时,另一个线程同时对集合进行了修改,就会抛出这个异常。引用\[2\]中的代码展示了一个可能导致这个异常的情况,其中多个线程同时向一个ArrayList中添加元素。由于ArrayList不是线程安全的,所以在多线程环境下进行修改操作会导致并发修改异常。引用\[3\]中提供了一种解决方案,使用Collections工具类的synchronizedList方法可以将ArrayList转换为线程安全的List,从而避免并发修改异常的发生。 #### 引用[.reference_title] - *1* [Error querying database. Cause: java.util.ConcurrentModificationException](https://blog.csdn.net/bengbuguang4321/article/details/119969155)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [出现了java.util.ConcurrentModificationException异常以及解决方案](https://blog.csdn.net/chuyouyinghe/article/details/127794442)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值