使用Iterator的ConcurrentModificationException

时间:2015-01-18 11:56:25

标签: java iterator

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

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)

2 个答案:

答案 0 :(得分:3)

您必须修改列表:

  1. pollKeyboard方法中的迭代器内部,而不使用迭代器上的addremove方法;或
  2. 在另一个帖子中
  3. 因此,您的异常是预期的行为。从the docs开始,如果你有一个线程迭代列表:

      

    如果在创建迭代器之后的任何时候对列表进行结构修改,除非通过迭代器自己的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锁定。它们都取决于您的确切要求。

答案 1 :(得分:-1)

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

ConcurrentModificationException

您可以使用navite java concurrent collestions代替。它们是线程安全的。然而,创建immutable collections是一个很好的习惯 - 它们是线程安全的,并强制您设计可靠的代码。