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());
}
}
}
其他办法:
还有一种方法,就是在集合remove之前,迭代器也remove,即:
iter.remove();
list.remove(user);
这样就不用新建集合存放了
例:
Iterator.remove() 可以更优雅地实现。
遍历删除元素部分代码更新如下:
for (Iterator it = userSet.iterator(); it.hasNext();) { User user = (User) it.next(); if (user.getId() == 1) { //delList.add(user); it.remove(); } if (user.getId() == 2) { user.setName("zhangsan"); }}//userSet.removeAll(delList); |
java.util.ConcurrentModificationException 解决办法(转)的更多相关文章
- java.util.ConcurrentModificationException 解决办法
在使用iterator.hasNext()操作迭代器的时候,如果此时迭代的对象发生改变,比如插入了新数据,或者有数据被删除. 则使用会报以下异常:Java.util.ConcurrentModific ...
- java.util.ConcurrentModificationException 解决办法(转载)
今天在项目的中有一个需求,需要在一个Set类型的集合中删除满足条件的对象,这时想当然地想到直接调用Set的remove(Object o)方法将指定的对象删除即可,测试代码: public cla ...
- java.util.ConcurrentModificationException解决详解
异常产生 当我们迭代一个ArrayList或者HashMap时,如果尝试对集合做一些修改操作(例如删除元素),可能会抛出java.util.ConcurrentModificationExceptio ...
- intellij idea导入不了java.util.Date解决办法
可以在Settings -> Editor -> General -> Auto Import,将Exclude中的java.util.Date删除.
- java.util.NoSuchElementException解决办法
报错代码 public void switchToNewWindow(){ //得到当前句柄 String currentWindow = driver.getWindowHandle(); //得到 ...
- java.util.ConcurrentModificationException的解决办法
今天在使用iterator.hasNext()操作迭代器的时候,当迭代的对象发生改变,比如插入了新数据,或者有数据被删除. 编译器报出了以下异常: Exception in thread " ...
- java.util.ConcurrentModificationException异常原因及解决方法
在java语言中,ArrayList是一个很常用的类,在编程中经常要对ArrayList进行删除操作,在使用remove方法对ArrayList进行删除操作时,报java.util.Concurren ...
- java.util.ConcurrentModificationException异常的解决
问题复现: List<String> list = new ArrayList<>();list.add("11");list.add("55&q ...
- java.util.ConcurrentModificationException 异常解决的方法及原理
近期在修程序的bug,发现后台抛出下面异常: Exception in thread "main" java.util.ConcurrentModificationExceptio ...
随机推荐
- 使用Struts2 验证框架,验证信息重复多次出现
版权声明:本文为博主原创文章,未经博主允许不得转载. 问题描述:第一次提交表单.某个数据不符合规则,就会出现一条错误信息.再次提交,上次显示的错误信息不消失,又多出一条一模一样的错误信息.提交几次,就 ...
- 用NOPI将图片二进制流导出到Excel
这儿采取的是将图片的二进制流导出到Excel,直接上代码: /// <summary> /// DataTable导出到Excel的MemoryStream /// </summar ...
- php魔术方法 http_build_query使用
最近在做一个项目使用到 http_build_query 这个魔术方法很好用,它可以将一个数组转换成这样的格式: 比如 $_arr = array('action'=>'show','page' ...
- extern 数组
最近比较关注C++对象的Linkage类型,然后今天突然想起extern数组这个奇葩的东西,稍微折腾了一下,顺手写个随笔. 首先在cpp中定义几个数组: ,,,,}; ,,,,}; ,,,,}; 然后 ...
- 《Usermod:user lee is currently logged in 家目录不能改变解决方法》
前面短时间自己玩samba服务时,上面的所有服务都做好了,家目录死活就是不能访问,删掉自己的smb.conf文件,自己到别的服务上用rsync同步过来的文件,启动服务家目录还是不能访问,排了一下午,终 ...
- Linux操作杂记
centos7修改默认运行等级 查看当前默认运行等级: systemctl get-dafault 修改默认运行等级为5: systemctl set-default graphical.target ...
- Redis源码研究--redis.h
------------7月3日------------ /* The redisOp structure defines a Redis Operation, that is an instance ...
- php生成txt文件换行问题
用双引号即"\r\n"换行,不能用单引号即'\r\n'.
- 学习php中常用语句与函数
1.while循环多用于不清楚循环次数的情况下,如需要把从数据库中读取出的多条记录(不清楚到底有多少条)并且要根据某个字段的值进行分类,每类值的具体数目,如下图: 其中选项有三种值,对每个值的票数时行 ...
- Mac上安装brew
用过ubuntu系统的都知道,上面有一个命令apt-get 很方便可以快速的安装很多软件 特别lamp环境 都是一键安装. 在mac上也有类似的命令 brew brew用法可以访问官网地址 http ...