欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

迭代器生成器可迭代对象_使用迭代器时如何避免ConcurrentModificationException

发布时间:2023/12/3 56 豆豆
生活随笔 收集整理的这篇文章主要介绍了 迭代器生成器可迭代对象_使用迭代器时如何避免ConcurrentModificationException 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

迭代器生成器可迭代对象

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的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。