迭代器生成器可迭代对象

Java Collection类是快速失败的,这意味着如果在使用迭代器遍历某个线程的同时更改了Collection,则iterator.next()将抛出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相关推荐

  1. python3迭代器和可迭代对象_一文读懂 Python3 可迭代对象、迭代器、生成器区别...

    笔者学习Python已有一段时间,一直以为对于可迭代对象(iterable).迭代器(iterator).生成器(generator)有一定理解了,直到看到<流畅的python>中的讲解才 ...

  2. python迭代器和可迭代对象_python tips:迭代器与可迭代对象

    for循环 1 for i ins:2 print(i) 在上述for循环中,不断地将s中的值赋值给i,然后打印出来.这种只针对s中元素的循环称为对s的迭代,能够迭代的s称为可迭代的. python为 ...

  3. python手写一个迭代器_搞清楚 Python 的迭代器、可迭代对象、生成器

    很多伙伴对 Python 的迭代器.可迭代对象.生成器这几个概念有点搞不清楚,我来说说我的理解,希望对需要的朋友有所帮助. 1 迭代器协议 迭代器协议是核心,搞懂了这个,上面的几个概念也就很好理解了. ...

  4. python迭代器和可迭代对象的关系_生成器、迭代器、可迭代对象的关系

    先把生成器.迭代器.可迭代对象三者的关系总结下,再解释概念.一图胜千言: 一.什么是可迭代对象 迭代是访问集合元素的一种方式.直接作用于for循环的数据类型有以下几种:一类是集合数据类型,如list. ...

  5. 迭代器、可迭代对象与生成器

    Iterator 与 gerater的作用是优化内存,当处理大文件,大数据的时候可以使用. 1. 对大列表进行优化 2. 大文件的优化 一.基本概念 迭代器: 一种数据类型,用来处理大数据 可迭代对象 ...

  6. 生成器、迭代器、可迭代对象三者的联系和区别

    生成器.迭代器.可迭代对象的联系和区别 可迭代对象 定义 判断 迭代器 概念 判断 生成器 概念 yield关键字 实例①: 实例②:yield生成器实现斐波那契数列 实例③:send()方法修改生成 ...

  7. 生成器、迭代器、可迭代对象

    本节内容 列表生成式 生成器(Generator) 可迭代对象(Iterable) 迭代器(Iterator) 生成器.迭代器.可迭代对象关系 列表生成式 列表生成式是 python 中的一种语法糖, ...

  8. python迭代器_使用Python的迭代器遍历可迭代对象

    迭代器也是用来遍历对象成员的,前面讨论过使用for循环遍历序列对象成员,为什么Python还要提供迭代器呢? 1.为什么要使用迭代器? 使用for循环可以遍历序列对象,列表.元组.字符串都是序列对象, ...

  9. 迭代器与可迭代对象的区别以及判断方法

    迭代是指重复的过程,是迭代取值的工具,迭代中的每一次重复都是基于上次一结果,提供了一种通用的不依赖索引的迭代取值方式. 可迭代对象可以通过 isinstance(obj,Iterable)来查看 fr ...

最新文章

  1. 2021下半年,我只想用Python搞钱!
  2. java web手动部署_tomcat手动部署web项目的方法
  3. Android Studio 更换国内源下载依赖库
  4. AWS_EC2_Oracle安装教程
  5. 瑞士电信vCPE商用落地 华三通信NFV方案成最大功臣
  6. 手机端网站测试用什么软件,3款优秀的移动webAPP网站在线测试工具推荐
  7. 关于数据可视化的思考小结
  8. Spring JTA应用JOTM Atomikos II JOTM
  9. 微服务化浪潮中,网易考拉借浪拉动业务极速增长
  10. Linux下安装配置git
  11. 达梦SQL格式化(美化器)
  12. android gps测速算法,GPS定位与测速算法研究
  13. 对Si446x驱动库的一些修改
  14. 从高中编码员到国际技术演讲者— Arun Michael Dsouza访谈
  15. laravel-excel 表格 文档翻译笔记
  16. 第三方远程控制工具TeamViewer的安装和使用教程,可下载window版和linux版,windows使用虚拟机可以与linux之间通讯
  17. 使用Godaddy续费我的域名时遇到支付问题
  18. scratch项目学习计划
  19. ue4html插件,【UE4插件Mirror】全球超千万Maya用户终于可以高质量实时渲染了
  20. 杭电数电实验(二)译码器

热门文章

  1. 2018蓝桥杯省赛---java---C---9(小朋友崇拜圈)
  2. 转:springboot servlet使用配置
  3. sql注入攻击和PreparedStatement有效防止sql注入攻击
  4. jdk 9和jdk8_JDK 9是某些功能的终结
  5. javadocs_不会吸引人的JavaDocs源样本
  6. 抽象工厂和工厂方法示例_工厂方法设计模式示例
  7. hazelcast入门教程_Hazelcast入门指南第7部分
  8. gradle引入依赖:_Gradle善良:获得更多的依赖性见解
  9. 您需要了解的有关UI测试的所有信息
  10. 通过SSL发送的Java邮件