【问题标题】:Reason for ConcurrentModificationException on ArrayLists iterator.next()ArrayLists iterator.next() 上 ConcurrentModificationException 的原因
【发布时间】:2023-04-06 06:37:02
【问题描述】:

我不知道为什么在迭代 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;
}

谁能告诉我问题的根源是什么?

【问题讨论】:

  • @newbieee:虽然演员阵容是不必要的,但这不是问题的原因。
  • 您没有添加或删除 currentOrders 的任何值,对吧?
  • 您需要在此处粘贴更多代码,您正在修改 currentOrders。
  • 您是否有任何其他线程可能正在访问由 strategy.process() 方法返回的 currentOrders 列表?
  • 在迭代之前尝试复制到 ArrayList - 不是解决方案,但可能有助于定位问题List&lt;Order&gt; currentOrders = new ArrayList&lt;&gt;(strategy.process(storageObject));

标签: java arraylist concurrentmodification


【解决方案1】:

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

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

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

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

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

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

希望这会有所帮助。

【讨论】:

    【解决方案2】:

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

    尝试用synchronized(currentOrders) { /* YOUR LAST CODE */ } 包围你的if。 我不确定,但请尝试一下。

    【讨论】:

      【解决方案3】:

      根据strategy.process(..) 的实现,这个实现可能仍然引用了它作为结果传回的列表。如果此实现中涉及多个线程,则列表可能会被这些线程之一修改,即使在它被传回之后也是如此。 (如果你知道“Future”模式,你也许可以想象一个方法立即返回一个空 List 并稍后使用另一个线程添加实际结果的实现)

      您可以尝试“围绕”结果列表创建一个新的 ArrayList 并迭代这个复制的列表。

      【讨论】:

        【解决方案4】:

        您可能想阅读this SO 帖子。如果看不到问题出在哪里,基本上切换并使用 CopyOnWriteArrayList。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-02-10
          • 1970-01-01
          • 2015-09-15
          • 2011-08-29
          • 1970-01-01
          • 2012-04-17
          相关资源
          最近更新 更多