我使用迭代器循环遍历集合,如下所示:
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)
答案 0 :(得分:3)
您必须修改列表:
pollKeyboard
方法中的迭代器内部,而不使用迭代器上的add
或remove
方法;或因此,您的异常是预期的行为。从the docs开始,如果你有一个线程迭代列表:
如果在创建迭代器之后的任何时候对列表进行结构修改,除非通过迭代器自己的remove或add方法,迭代器将抛出ConcurrentModificationException
如果多个线程一次使用该列表:
请注意,此实现未同步。如果多个线程同时访问ArrayList实例,并且至少有一个线程在结构上修改了列表,必须在外部进行同步
如果只有一个线程访问该列表,请确保使用entityItr.remove
或add
方法修改列表。
对于多线程情况,如果您没有可用的锁定对象,则可以使用Collections.synchronizedList
。
首先将单个中央引用存储到列表中:
entityList = Collections.synchronizedList(theOriginalArrayList);
然后访问它(与所有读者和作者一起):
synchronized (entityList) {
// Readers might do:
itr = entityList.iterator();
while (i.hasNext())
... do stuff ...
}
还有其他方法可以同步多线程访问,包括将列表复制到数组(在同步块内)并迭代它以进行读取,或使用ReadWrite
锁定。它们都取决于您的确切要求。
答案 1 :(得分:-1)
看起来有另一个线程使用相同的集合,并在此代码迭代集合时对其进行修改。
ConcurrentModificationException
您可以使用navite java concurrent collestions代替。它们是线程安全的。然而,创建immutable collections是一个很好的习惯 - 它们是线程安全的,并强制您设计可靠的代码。