ArrayLists上的ConcurrentModificationException的原因iterator.next()

时间:2014-06-30 07:53:58

标签: java arraylist concurrentmodification

我不知道为什么迭代ArrayList时会发生ConcurrentModificationException。 ArrayList是methode范围的,因此执行相同代码的其他线程不应该看到它。至少如果我正确地理解了多线程和变量范围。

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 个答案:

答案 0 :(得分:2)

如果您已阅读ConcurrentModifcationException的Java文档:

它清楚地说明了它发生的条件:

  

检测到并发的方法可能抛出此异常   当不允许这种修改时修改对象。   例如,一个线程通常不允许修改   一个集合,而另一个线程正在迭代它。一般来说,   在这些情况下,迭代的结果是不确定的。   一些迭代器实现(包括所有通用的实现)   由JRE提供的目的集合实现可以选择   如果检测到此行为,则抛出此异常。那个迭代器   这被称为故障快速迭代器,因为它们很快就会失败   干净利落,而不是冒着任意的,非确定性的行为冒险   未来不确定的时间。

     

请注意,此异常并不总是表示对象具有   由另一个线程同时修改。如果是单线程   发出一系列违反合同的方法调用   一个对象,该对象可能抛出此异常。例如,如果是   线程在迭代时直接修改集合   使用失败快速迭代器进行集合,迭代器将抛出此异常   异常。

     

请注意,通常情况下无法保证快速失败的行为   说话,在场的情况下不可能做出任何硬性保证   不同步的并发修改。失败快速操作投掷   ConcurrentModificationException是尽力而为的。因此,它   编写一个依赖于此异常的程序是错误的   它的正确性:应该只使用ConcurrentModificationException   检测错误。

在您说的情况下,您没有多个线程访问此列表。如果你从迭代器读取的单个线程也可能试图写入它,那么它仍然可能如上所述。

希望这有帮助。

答案 1 :(得分:0)

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

尝试通过synchronized(currentOrders) { /* YOUR LAST CODE */ }包围你的if。 我不确定这个但是试一试。

答案 2 :(得分:0)

根据strategy.process(..)的实现,可能是这个实现仍然引用了它作为结果传回的List。如果此实现中涉及多个线程,则即使在传回结果后,也可能由其中一个线程修改List。 (如果您知道&#34; Future&#34;模式,您可以想象一个实现,其中方法立即返回空List并稍后使用另一个Thread添加实际结果)

您可以尝试创建一个新的ArrayList&#34;&#34;结果列表并遍历此复制列表。

答案 3 :(得分:0)

您可能希望阅读this SO帖子。如果你看不到问题的来源,基本上就切换并使用CopyOnWriteArrayList。