我使用迭代器遍历一个集合,如下所示:
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)
您必须修改列表之一:
pollKeyboard
add
remove
因此,您的例外是预期的行为。从该文档,如果你有一个线程遍历列表:
如果在创建迭代器后的任何时间对列表进行结构修改,则除了通过迭代器自己的remove或add方法以任何方式进行修改外,迭代器都会引发ConcurrentModificationException
并且如果多个线程一次使用该列表:
请注意,此实现未同步。如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改列表, 则必须在外部进行同步
如果只有一个线程访问列表,请确保使用entityItr.remove或add方法来修改列表。
entityItr.remove
对于多线程情况,Collections.synchronizedList如果没有可用的锁定对象,则可以使用。
Collections.synchronizedList
首先,将对列表的单个中央引用存储为:
entityList = Collections.synchronizedList(theOriginalArrayList);
然后以以下方式访问它(所有读者和作家):
synchronized (entityList) { // Readers might do: itr = entityList.iterator(); while (i.hasNext()) ... do stuff ... }
还有其他同步多线程访问的方法,包括将列表复制到数组(在同步块内部)并对其进行迭代以进行读取或使用ReadWrite锁。它们都取决于您的确切要求。
ReadWrite