迭代器生成器可迭代对象_使用迭代器时如何避免ConcurrentModificationException
迭代器生成器可迭代对象
在多线程以及单线程环境中都可能出现这种情况。
让我们通过以下示例探索这种情况:
import java.util.*;public class IteratorExample {public static void main(String args[]){List<String> myList = new ArrayList<String>();myList.add("1");myList.add("2");myList.add("3");myList.add("4");myList.add("5");Iterator<String> it = myList.iterator();while(it.hasNext()){String value = it.next();System.out.println("List Value:"+value);if(value.equals("3")) myList.remove(value);}Map<String,String> myMap = new HashMap<String,String>();myMap.put("1", "1");myMap.put("2", "2");myMap.put("3", "3");Iterator<String> it1 = myMap.keySet().iterator();while(it1.hasNext()){String key = it1.next();System.out.println("Map Value:"+myMap.get(key));if(key.equals("2")){myMap.put("1","4");//myMap.put("4", "4");}}}
}
输出为:
List Value:1
List Value:2
List Value:3
Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)at java.util.AbstractList$Itr.next(AbstractList.java:343)at com.journaldev.java.IteratorExample.main(IteratorExample.java:27)
从输出堆栈跟踪中可以明显看出,当我们调用迭代器next()函数时,异常即将到来。 如果您想知道Iterator如何检查修改,则它的实现存在于AbstractList类中,其中定义了一个int变量modCount,该变量提供了更改列表大小的次数。 该值在每个next()调用中使用,以检查功能checkForComodification()中是否有任何修改。
现在,注释列表部分并再次运行该程序。
输出将是:
Map Value:3
Map Value:2
Map Value:4
由于我们正在更新myMap中的现有键值,因此其大小没有更改,并且没有收到ConcurrentModificationException。 请注意,输出结果可能在您的系统中有所不同,因为HashMap键集的排序不像list那样。 如果您将在HashMap中添加新键值的语句取消注释,则将导致ConcurrentModificationException。
要在多线程环境中避免ConcurrentModificationException:
1.您可以将列表转换为数组,然后在数组上进行迭代。 这种方法适用于中小型列表,但是如果列表很大,则对性能的影响很大。
2.您可以通过将列表放在同步块中来在锁定时锁定列表。 不建议使用此方法,因为它将停止多线程的好处。
3.如果使用的是JDK1.5或更高版本,则可以使用ConcurrentHashMap和CopyOnWriteArrayList类。 这是推荐的方法。
要在单线程环境中避免ConcurrentModificationException:
您可以使用迭代器remove()函数从基础集合对象中删除该对象。 但是在这种情况下,您可以从列表中删除同一对象,而不能删除任何其他对象。
让我们使用并发集合类运行示例:
package com.journaldev.java;import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;public class ThreadSafeIteratorExample {public static void main(String[] args) {List<String> myList = new CopyOnWriteArrayList<String>();myList.add("1");myList.add("2");myList.add("3");myList.add("4");myList.add("5");Iterator<String> it = myList.iterator();while(it.hasNext()){String value = it.next();System.out.println("List Value:"+value);if(value.equals("3")){myList.remove("4");myList.add("6");myList.add("7");}}System.out.println("List Size:"+myList.size());Map<String,String> myMap = new ConcurrentHashMap<String,String>();myMap.put("1", "1");myMap.put("2", "2");myMap.put("3", "3");Iterator<String> it1 = myMap.keySet().iterator();while(it1.hasNext()){String key = it1.next();System.out.println("Map Value:"+myMap.get(key));if(key.equals("1")){myMap.remove("3");myMap.put("4", "4");myMap.put("5", "5");}}System.out.println("Map Size:"+myMap.size());}}
输出为:
List Value:1
List Value:2
List Value:3
List Value:4
List Value:5
List Size:6
Map Value:1
Map Value:null
Map Value:4
Map Value:2
Map Size:4
从上面的示例可以清楚地看出:
1.可以修改Concurrent Collection类,避免ConcurrentModificationException 。
2.对于CopyOnWriteArrayList ,迭代器不适应列表中的更改,并且可以处理原始列表。
3.对于ConcurrentHashMap ,行为并不总是相同的。
条件:
if(key.equals("1")){myMap.remove("3");
输出为:
Map Value:1
Map Value:null
Map Value:4
Map Value:2
Map Size:4
它正在使用添加了键“ 4”的新对象。 但不是下一个键为“ 5”的对象。
现在,如果我将条件更改为
if(key.equals("3")){myMap.remove("2");
输出为:
Map Value:1
Map Value:3
Map Value:null
Map Size:4
在这种情况下,它不考虑新添加的对象。
因此,如果您使用的是ConcurrentHashMap,请避免添加新对象,因为可以根据键集对其进行处理。 请注意,同一程序可以在您的系统中打印不同的值,因为HashMap键集没有任何顺序。
额外的浇头:
for(int i = 0; i<myList.size(); i++){System.out.println(myList.get(i));if(myList.get(i).equals("3")){myList.remove(i);i--;myList.add("6");}
}
如果您在单线程环境中工作,并且希望您的代码处理列表中额外添加的对象,则可以使用以下代码并避免使用迭代器。
请注意,由于要删除同一对象,所以要减少计数器,如果必须删除下一个或更远的对象,则不需要减少计数器。
自己尝试。
参考:在JournalDev上 使用 JCG合作伙伴提供的迭代器时如何避免ConcurrentModificationException 。
相关文章:
- Java最佳实践– Vector vs ArrayList vs HashSet
- Java最佳实践–队列之战和链接的ConcurrentHashMap
- Java Fork / Join进行并行编程
- ConcurrentLinkedHashMap v 1.0.1发布
- 阻塞队列示例以执行命令
- 信号量示例限制URL连接
- 执行命令的同步队列示例
- 更一般的等待/通知机制的CountDownLatch示例
翻译自: https://www.javacodegeeks.com/2011/05/avoid-concurrentmodificationexception.html
迭代器生成器可迭代对象
迭代器生成器可迭代对象_使用迭代器时如何避免ConcurrentModificationException相关推荐
- python3迭代器和可迭代对象_一文读懂 Python3 可迭代对象、迭代器、生成器区别...
笔者学习Python已有一段时间,一直以为对于可迭代对象(iterable).迭代器(iterator).生成器(generator)有一定理解了,直到看到<流畅的python>中的讲解才 ...
- python迭代器和可迭代对象_python tips:迭代器与可迭代对象
for循环 1 for i ins:2 print(i) 在上述for循环中,不断地将s中的值赋值给i,然后打印出来.这种只针对s中元素的循环称为对s的迭代,能够迭代的s称为可迭代的. python为 ...
- python手写一个迭代器_搞清楚 Python 的迭代器、可迭代对象、生成器
很多伙伴对 Python 的迭代器.可迭代对象.生成器这几个概念有点搞不清楚,我来说说我的理解,希望对需要的朋友有所帮助. 1 迭代器协议 迭代器协议是核心,搞懂了这个,上面的几个概念也就很好理解了. ...
- python迭代器和可迭代对象的关系_生成器、迭代器、可迭代对象的关系
先把生成器.迭代器.可迭代对象三者的关系总结下,再解释概念.一图胜千言: 一.什么是可迭代对象 迭代是访问集合元素的一种方式.直接作用于for循环的数据类型有以下几种:一类是集合数据类型,如list. ...
- 迭代器、可迭代对象与生成器
Iterator 与 gerater的作用是优化内存,当处理大文件,大数据的时候可以使用. 1. 对大列表进行优化 2. 大文件的优化 一.基本概念 迭代器: 一种数据类型,用来处理大数据 可迭代对象 ...
- 生成器、迭代器、可迭代对象三者的联系和区别
生成器.迭代器.可迭代对象的联系和区别 可迭代对象 定义 判断 迭代器 概念 判断 生成器 概念 yield关键字 实例①: 实例②:yield生成器实现斐波那契数列 实例③:send()方法修改生成 ...
- 生成器、迭代器、可迭代对象
本节内容 列表生成式 生成器(Generator) 可迭代对象(Iterable) 迭代器(Iterator) 生成器.迭代器.可迭代对象关系 列表生成式 列表生成式是 python 中的一种语法糖, ...
- python迭代器_使用Python的迭代器遍历可迭代对象
迭代器也是用来遍历对象成员的,前面讨论过使用for循环遍历序列对象成员,为什么Python还要提供迭代器呢? 1.为什么要使用迭代器? 使用for循环可以遍历序列对象,列表.元组.字符串都是序列对象, ...
- 迭代器与可迭代对象的区别以及判断方法
迭代是指重复的过程,是迭代取值的工具,迭代中的每一次重复都是基于上次一结果,提供了一种通用的不依赖索引的迭代取值方式. 可迭代对象可以通过 isinstance(obj,Iterable)来查看 fr ...
最新文章
- 2021下半年,我只想用Python搞钱!
- java web手动部署_tomcat手动部署web项目的方法
- Android Studio 更换国内源下载依赖库
- AWS_EC2_Oracle安装教程
- 瑞士电信vCPE商用落地 华三通信NFV方案成最大功臣
- 手机端网站测试用什么软件,3款优秀的移动webAPP网站在线测试工具推荐
- 关于数据可视化的思考小结
- Spring JTA应用JOTM Atomikos II JOTM
- 微服务化浪潮中,网易考拉借浪拉动业务极速增长
- Linux下安装配置git
- 达梦SQL格式化(美化器)
- android gps测速算法,GPS定位与测速算法研究
- 对Si446x驱动库的一些修改
- 从高中编码员到国际技术演讲者— Arun Michael Dsouza访谈
- laravel-excel 表格 文档翻译笔记
- 第三方远程控制工具TeamViewer的安装和使用教程,可下载window版和linux版,windows使用虚拟机可以与linux之间通讯
- 使用Godaddy续费我的域名时遇到支付问题
- scratch项目学习计划
- ue4html插件,【UE4插件Mirror】全球超千万Maya用户终于可以高质量实时渲染了
- 杭电数电实验(二)译码器
热门文章
- 2018蓝桥杯省赛---java---C---9(小朋友崇拜圈)
- 转:springboot servlet使用配置
- sql注入攻击和PreparedStatement有效防止sql注入攻击
- jdk 9和jdk8_JDK 9是某些功能的终结
- javadocs_不会吸引人的JavaDocs源样本
- 抽象工厂和工厂方法示例_工厂方法设计模式示例
- hazelcast入门教程_Hazelcast入门指南第7部分
- gradle引入依赖:_Gradle善良:获得更多的依赖性见解
- 您需要了解的有关UI测试的所有信息
- 通过SSL发送的Java邮件