ConcurrentModificationException从迭代器移除元素

时间:2019-01-23 08:58:53

标签: java iterator

返回了ConcurrentModificationException,但从地图上删除了一个条目,但是我看不到有什么问题。

    Iterator<String> mapIterator = this.attributeMap.keySet().iterator();
    while (mapIterator.hasNext())
    {
        String attributeName = mapIterator.next();
        if (attributeName.matches(pattern))
        {
            mapIterator.remove();
        }
    }

2 个答案:

答案 0 :(得分:1)

您可以查看有关CME的一些详细信息:https://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html

  

检测到对象并发修改的方法可能会抛出此异常,而这种修改是不允许的。   例如,通常不允许一个线程修改Collection而另一个线程对其进行迭代。通常,在这些情况下,迭代的结果是不确定的。如果检测到此行为,则某些Iterator实现(包括JRE提供的所有通用集合实现的实现)可能会选择抛出此异常。执行此操作的迭代器称为快速失败迭代器,因为它们会快速干净地失败,而不是在未来不确定的时间冒任意,不确定的行为的风险。

以下是Baeldung提供的一些解决方案,链接如下:

  1. 直接使用迭代器
  2. 在迭代过程中不删除
  3. 使用removeIf()
  4. 使用流过滤

您可以在他的网站上查看每种解决方案的详细信息,以避免使用CME:https://www.baeldung.com/java-concurrentmodificationexception

希望这会有所帮助。

答案 1 :(得分:1)

在这种情况下,     mapIterator.next() 抛出ConcurrentModificationException

其背后的原因是:
有一个int变量modCount,它提供了更改列表大小的次数,此值在每次next()调用中都使用,以检查函数{{1}中是否有任何修改}。
如果checkForComodification()在迭代对象中的mapIterator.next()中发现了变化,则它将抛出modCount

为避免这种情况,请遵循以下几点:

  1. 您可以将列表转换为数组,然后在数组上进行迭代。这种方法适用于中小型列表,但是如果列表很大,则会对性能产生很大影响。

  2. 您可以通过将列表放在同步块中来在锁定时锁定列表。不建议使用这种方法,因为它将停止多线程的好处。

  3. 如果使用的是JDK1.5或更高版本,则可以使用ConcurrentHashMap和CopyOnWriteArrayList类。这是推荐的方法。