ArrayList的iterator.next()方法出现ConcurrentModificationException的原因

4

我不知道为什么在遍历ArrayList时会出现ConcurrentModificationException异常。这个ArrayList是方法作用域的,因此其他执行相同代码的线程不应该能够看到它。至少,如果我正确理解多线程和变量作用域的话。

Caused by: java.util.ConcurrentModificationException
at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:64)
at com....StrategyHandler.applyStrategy(StrategyHandler.java:184)

private List<Order> applyStrategy(StorageObjectTree storageObjectTree) {
    ...
    List<OrderHeader> finalList = new ArrayList<Order>();

    for (StorageObject storageObject : storageObjectTree.getStorageObjects()) {

        List<Order> currentOrders = strategy.process(storageObject);
        ...
        if (currentOrders != null) {
          Iterator<Order> iterator = currentOrders.iterator();
          while (iterator.hasNext()) {
            Order order = (Order) iterator.next();     // line 64
            // read some values from order
          }

          finalList.addAll(currentOrders);
        }
    }

    return finalList;
}

有人能给我一个提示,问题的根源可能是什么吗?

4
虽然这个演员阵容不必要,但它并非问题的根源。 - Jon Skeet
1
你没有添加或删除 currentOrders 中的任何值,对吗? - paul
1
你需要在这里粘贴更多的代码,因为你正在修改currentOrders。 - Vipin
2
你有没有其他线程可能正在访问由strategy.process()方法返回的currentOrders列表? - pillingworth
2
尝试在迭代之前将其复制到ArrayList中 - 这不是解决方案,但可能有助于定位问题。List<Order> currentOrders = new ArrayList<>(strategy.process(storageObject)); - pillingworth
显示剩余10条评论
4个回答

2
如果您已经阅读了Java文档中的ConcurrentModificationException:ConcurrentModifcationException,它清楚地说明了出现此异常的条件。
这个异常可能会被检测到并抛出,当一个对象正在被修改而这种修改不被允许时,在一些方法中。例如,一个线程在另一个线程正在迭代它的集合时修改集合通常是不允许的。在这些情况下,迭代的结果是未定义的。某些迭代器实现(包括JRE提供的所有通用集合实现)可能会选择在检测到此行为时抛出此异常。如果这样做,这些迭代器被称为“快速失败迭代器”,因为它们会快速而干净地失败,而不是冒着在未来的不确定时间内出现任意、非确定性行为的风险。
请注意,此异常并不总是表明对象已被不同的线程同时修改。如果一个单独的线程发出违反对象协议的方法调用序列,那么对象可能会抛出此异常。例如,如果一个线程直接修改集合,而另一个线程正在使用快速失败迭代器迭代该集合,则迭代器将抛出此异常。
请注意,由于存在不同步的并发修改,不能保证快速失败行为。快速失败操作尽力抛出ConcurrentModificationException异常。因此,编写依赖此异常来保证正确性的程序是错误的:ConcurrentModificationException应该仅用于检测错误。
在您的情况中,正如您所说,您没有多个线程访问此列表。但是,根据上面第二段中的说明,如果正在读取迭代器的单个线程也尝试对其进行写操作,这仍然可能发生。
希望这能帮助到您。

0

当您更改/添加/删除列表中的值并同时迭代它时,会发生此异常。如果您同时使用多个线程...

尝试通过synchronized(currentOrders) { /* YOUR LAST CODE */ }来包围您的if语句。 我不确定这一点,但请尝试。


0

根据strategy.process(..)的实现方式,它可能仍然引用作为结果返回的列表。如果多个线程参与此实现,则可能会在将其作为结果返回后被其中一个线程修改。

(如果您了解“Future”模式,则可以想象一种实现方式,其中方法立即返回空列表,并使用另一个线程稍后添加实际结果)

您可以尝试创建一个新的ArrayList“around”结果列表,并遍历此复制列表。


0

你可能想要阅读this的SO帖子。基本上,如果你无法找出问题的根源,可以考虑使用Switch并使用CopyOnWriteArrayList。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接