【问题标题】:ConcurrentModificationException thrown while removing element from the list从列表中删除元素时引发 ConcurrentModificationException
【发布时间】:2018-06-26 14:24:47
【问题描述】:

我必须从存储中迭代的列表中删除元素。即使使用迭代器,它也会抛出 ConcurrentModificationException。此代码将在活动结束时执行。参考:iter1.remove()。请建议是否有任何解决方法。

List<OfflineCommand> l_loc = (List<OfflineCommand>) Storage.getInstance().readObject("LocationTest"); 
            if (l_loc != null) {                
                boolean flgSuccess = true;
                ListIterator<OfflineCommand> iter1 = l_loc.listIterator();
                while (iter1.hasNext()) {
                    OfflineCommand oc = iter1.next();
                    flgSuccess = executeOfflineCommand(oc);
                    if (!flgSuccess) {
                        break;
                    } else {
                        iter1.remove();
                    }
                }
            }

在另一个地方,我使用以下代码每分钟将条目添加到同一个列表中。

 List<OfflineCommand> l_noAppt = Storage.getInstance().readObject("LocationTest");
            if (l_noAppt == null) {
                l_noAppt = new ArrayList<>();
            }
            l_noAppt.add(new OfflineCommand(name, args));
            Storage.getInstance().writeObject("LocationTest", l_noAppt);

【问题讨论】:

  • 首先你说你的代码抛出异常。然后你说你不确定它是否会抛出异常。你自相矛盾。请解释一下。
  • 我无法预测导致问题的原因。我在项目中使用列表的位置添加了代码。谢谢

标签: codenameone


【解决方案1】:

在一个地方添加元素并在另一个地方同时移除元素需要同步。

A) 使用矢量

Vector 提供开箱即用的同步。但即使是 Vector,也不要使用 Iterator,因为您有并发修改。

// On the place where you create your list now, create a Vector,
// like ... = new Vector<...>() instead of ... = new ArrayList<...>().
// Just a cast is not sufficient of course.
Vector<OfflineCommand> l_loc = ...;
if (l_loc != null) {                
  boolean flgSuccess = true;
  while (!l_loc.isEmpty()) {
    OfflineCommand oc = l_loc.get(0);
    flgSuccess = executeOfflineCommand(oc);
    if (!flgSuccess) {
      break;
    } else {
      l_loc.remove(0);
    }
  }
}

优点:您不需要显式同步。您的代码保持紧凑。

B) 使用显式同步。

List<OfflineCommand> l_loc = ...;
if (l_loc != null) {                
  boolean flgSuccess = true;
  while (!l_loc.isEmpty()) {
    OfflineCommand oc = l_loc.get(0);
    flgSuccess = executeOfflineCommand(oc);
    if (!flgSuccess) {
      break;
    } else {
      synchronized (l_loc) {
        l_loc.remove(0);
      }
    }
  }
}

重要提示:在您将对象添加到此列表中的地方,您还应该使用同步:

synchronized(l_loc) {
  l_loc.add(...);
}

第二种方法不太可靠,因为您应该记住所有可以修改列表的地方并在那里使用同步。

这两种方法,A 和 B,都将解决并发修改的问题。

【讨论】:

  • 谢谢mentallurg。我将尝试 Vector 方法,看看这是否有效。谢谢
  • 它也没有工作。仍然抛出 ConcurrentModificationException
  • @user1678742:显示您的代码。我想刚刚用 Vector 替换了 List 并保留了 Iterator。正确的?不要使用 迭代器。在我的示例中,我不使用它。当许多线程同时向其添加或删除元素时,Vector 可以正常工作。但是VectorIterator不接受并发修改。不要使用 迭代器。而是使用任何正常的循环结构:whiledofor.
  • 这个答案是错误的。这些是两个单独的列表实例。他确实需要确保它们都在同一个线程中运行,以便它们从存储中写入/读取而不会相互覆盖
  • @Schai Almog:你读过这个问题吗?在另一个线程中,每分钟都会添加新元素。你不明白要求。这就是要求它应该同时修改正常工作。
【解决方案2】:

您的问题含糊不清。 为避免 ConcurrentModificationException,请使用 ConcurrentHashMap 并改用 FOR 循环。

【讨论】:

    【解决方案3】:

    一旦调用remove()Iterator 实例就会失效。有几种解决方法。由于您删除了所有元素,直到输入不成功,这样的事情将在iter1 = l_loc.listIterator(); 或上下文中起作用:

                while (iter1.hasNext()) {
                    OfflineCommand oc = iter1.next();
                    flgSuccess = executeOfflineCommand(oc);
                    if (!flgSuccess) {
                        break;
                    } else {
                        iter1.remove();
                        iter1 = l_loc.listIterator();
                    }
                }
    

    【讨论】:

    • 没有。你的说法是错误的。调用 remove 后,迭代器保持 有效
    • @Shai - 因为错误将在语句 iter1.remove() 中抛出,添加 iter1 = l_loc.listIterator();将无济于事,因为那时引发了错误。请指教。
    • @Shai。向量将与 CN1 中的存储一起工作吗?请指教。
    • 你真的试过这个吗?第一个 remove() 之后的下一个循环是失败的事情。
    • 是的,Shai。我试过了,它又开始失败了。有没有其他的选择。谢谢
    猜你喜欢
    • 2011-07-04
    • 1970-01-01
    • 2014-06-03
    • 2019-09-11
    • 1970-01-01
    • 2022-12-23
    • 1970-01-01
    • 2021-03-17
    • 1970-01-01
    相关资源
    最近更新 更多