【问题标题】:How can I fix Exception in thread "main" java.util.ConcurrentModificationException [duplicate]如何修复线程“main”中的异常 java.util.ConcurrentModificationException [重复]
【发布时间】:2013-10-01 11:03:27
【问题描述】:

我有 2 个 HashMap<Integer,Point3D> 对象名称是 positiveCoOrdinate and negativeCoOrdinates

我正在使用以下条件检查PositiveCoOrdinates。如果它满足添加到negativeCoOrdinates 并从positiveCoOrdinates 中删除的对应点。

  HashMap<Integer, Point3d> positiveCoOrdinates=duelList.get(1);
  HashMap<Integer, Point3d> negativecoOrdinates=duelList.get(2);
  //condition
  Set<Integer> set=positiveCoOrdinates.keySet();
    for (Integer pointIndex : set) {
        Point3d coOrdinate=positiveCoOrdinates.get(pointIndex);
        if (coOrdinate.x>xMaxValue || coOrdinate.y>yMaxValue || coOrdinate.z>zMaxValue) {
            negativecoOrdinates.put(pointIndex, coOrdinate);
            positiveCoOrdinates.remove(pointIndex);
        }
    }

在添加、删除时间时出现以下错误。

 Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$KeyIterator.next(Unknown Source)
at PlaneCoOrdinates.CoordinatesFiltering.Integration(CoordinatesFiltering.java:167)
at PlaneCoOrdinates.CoordinatesFiltering.main(CoordinatesFiltering.java:179)

对于我的测试,我在If 条件中提到了System.out.println(coOrdinate.x); 语句。它工作正常。

如果我在 If 条件中添加 2 行(我上面提到的),它会抛出错误。

我该如何解决这个问题。

谢谢。

【问题讨论】:

  • 使用entrySet()可以避免查找刚刚获得的密钥

标签: java


【解决方案1】:

最简单的方法是复制keySet:

  Set<Integer> set= new HashSet<Integer>(positiveCoOrdinates.keySet());

出现问题是因为您在使用 Iterator 迭代键时修改了 positiveCoOrdinates

您还可以重构代码并在条目集上使用迭代器。这将是一个更好的方法。

Set<Entry<Integer, Point3d>> entrySet = positiveCoOrdinates.entrySet();

    for (Iterator<Entry<Integer, Point3d>> iterator = entrySet.iterator(); iterator.hasNext();) {
        Entry<Integer, Point3d> entry = iterator.next();
        Point3d coOrdinate = entry.getValue();
        if (coOrdinate.x > xMaxValue || coOrdinate.y > yMaxValue
                || coOrdinate.z > zMaxValue) {
            Integer pointIndex = entry.getKey();
            negativecoOrdinates.put(pointIndex, coOrdinate);
            iterator.remove();
        }
    }

【讨论】:

  • 或者可以使用Iterator
  • 感谢它运行良好...
  • 这行得通,但由于我使用的是排序哈希映射,我需要使用 LinkedHashSet 的新实例来保持顺序。我不能考虑使用 iterator.remove() 删除项目,因为我正在跟踪辅助元素并在需要时与 it.next() 交换。根据情况,我应该删除辅助键而不是从 it.next() 方法检索的当前键,然后使用 Set 的新实例就可以了。我不能只使用 iterator.remove() 来做到这一点。
【解决方案2】:

当使用增强的for-each 循环时,您不能从迭代集合中remove()for-each 循环隐式使用 Iterator&lt;Integer&gt;JavaDoc 明确指出

这个类的所有“集合视图”返回的迭代器 方法”是快速失败的:如果地图在任何结构上被修改 迭代器创建后的时间,除了通过 迭代器自己的remove()方法,迭代器会抛出一个 ConcurrentModificationException。因此,面对并发 修改,迭代器快速而干净地失败,而不是 在不确定的时间冒着任意的、不确定的行为的风险 未来。

for-each 循环在内部创建一个迭代器并使用它来遍历集合。然后你改变集合的结构......并且迭代器必须失败。问题是您无权访问迭代器的方法,因此您必须明确使用Iterator&lt;Integer&gt;。生成的遍历字节码将是相同的,唯一的区别是您可以在遍历列表时从列表中删除元素。

Set<Integer> set = positiveCoOrdinates.keySet();
for (Iterator<Integer> iterator = set.iterator(); iterator.hasNext(); ) {
    Integer pointIndex = iterator.next();
    Point3d coOrdinate = positiveCoOrdinates.get(pointIndex);
    if (coOrdinate.x>xMaxValue || coOrdinate.y>yMaxValue || coOrdinate.z>zMaxValue) {
        negativecoOrdinates.put(pointIndex, coOrdinate);
        iterator.remove(pointIndex);    // this line changed!
    }
}

如果您不熟悉迭代器及其功能,请参阅the Oracle tutorial on Collections

Iterator 是一个对象,可让您遍历 集合并有选择地从集合中删除元素,如果 想要的。您可以通过调用 iterator() 来获得集合的 Iterator 方法。

请注意,Iterator.remove() 是修改 迭代期间的收集;如果 底层集合在迭代时以任何其他方式修改 正在进行中。

当您需要时使用Iterator 而不是for-each 构造:

  • 删除当前元素。 for-each 构造隐藏了迭代器,因此您不能调用 remove()。因此,for-each 构造不可用于过滤。

【讨论】:

    【解决方案3】:

    如果你想在运行时修改集合,你需要使用Iterator而不是增强的for循环。因为增强的 for 循环只提供只读功能。以下是迭代器示例:

    Iterator<Entity> iterator = collection.Iterator();
    while(iterator.hasNext()){
      //DO Your Stuff
      iterator.remove(); // this function call remove the element from collection at run time
    }
    

    【讨论】:

      【解决方案4】:

      正如 René 所指出的,这个非常常见的问题的原因是在另一个集合正在读取它的同时对其进行并发修改。

      您可以使用ConcurrentHashMapCopyOnWriteArrayLit 之类的集合,但请注意,这些方法可能有点像expensive,并且通过简单的代码更改程序来消除在迭代中读取同一集合将解决此类问题.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-01-05
        • 2021-02-10
        • 2017-09-24
        • 1970-01-01
        • 1970-01-01
        • 2018-09-15
        • 2015-08-07
        相关资源
        最近更新 更多