使用Iterator的ConcurrentModificationException

我正在使用迭代器循环集合,如下所示:

Iterator 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) 

您必须修改列表:

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

因此,您的exception是预期的行为。 从文档中 ,如果您有一个迭代列表的单个线程:

如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove或add方法之外,迭代器将抛出ConcurrentModificationException

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

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

解:

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

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

首先将单个中央引用存储到列表中:

 entityList = Collections.synchronizedList(theOriginalArrayList); 

然后访问它(与所有读者和作者):

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

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

它看起来有另一个线程使用相同的集合,并在此代码迭代集合时对其进行修改。

ConcurrentModificationException的

您可以使用navite java 并发collestions 。 它们是线程安全的。 然而,创建不可变集合是一个很好的习惯 – 它们是线程安全的,并强制您设计可靠的代码。