小编典典

使用Iterator的ConcurrentModificationException

java

我使用迭代器遍历一个集合,如下所示:

Iterator<Entity> entityItr = entityList.iterator();

    while (entityItr.hasNext())
    {
        Entity curr = entityItr.next();

        for (Component c : curr.getComponents())
        {
            if (c instanceof PlayerControlled)
            {
                ((PlayerControlled) c).pollKeyboard();  
            }
        }
    }

但是在下面的行中,我得到了ConcurrentModificationException

 Entity curr = entityItr.next();

当我不进行任何更改时,为什么会发生这种情况?

非常感谢

编辑-堆栈跟踪:

java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at cw.systems.Input.checkInputs(Input.java:31)
at cw.systems.Input.begin(Input.java:21)
at cw.misc.Game.render(Game.java:73)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:207)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)

阅读 236

收藏
2020-11-30

共1个答案

小编典典

您必须修改列表之一:

  1. pollKeyboard方法中的迭代器内部,而无需使用迭代器上的addremove方法;要么
  2. 在另一个线程中

因此,您的例外是预期的行为。从该文档,如果你有一个线程遍历列表:

如果在创建迭代器后的任何时间对列表进行结构修改,则除了通过迭代器自己的remove或add方法以任何方式进行修改外,迭代器都会引发ConcurrentModificationException

并且如果多个线程一次使用该列表:

请注意,此实现未同步。如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改列表, 则必须在外部进行同步

解:

如果只有一个线程访问列表,请确保使用entityItr.removeadd方法来修改列表。

对于多线程情况,Collections.synchronizedList如果没有可用的锁定对象,则可以使用。

首先,将对列表的单个中央引用存储为:

entityList = Collections.synchronizedList(theOriginalArrayList);

然后以以下方式访问它(所有读者和作家):

synchronized (entityList) {
  // Readers might do:
  itr = entityList.iterator();
  while (i.hasNext())
    ... do stuff ...
}

还有其他同步多线程访问的方法,包括将列表复制到数组(在同步块内部)并对其进行迭代以进行读取或使用ReadWrite锁。它们都取决于您的确切要求。

2020-11-30