ArrayLists中的Java并发(Threads)。经典for和foreach之间的区别

时间:2014-01-05 20:05:38

标签: java foreach iterator

我有一个与GalaxyInvaders克隆相关的问题。

forforeach迭代ArrayList之间有什么区别?

我正在使用ArrayLists循环修改foreach(更改变量/删除某些对象)(我在使用Semaphores执行此操作之前阻止了各个部分)。

问题是,当我使用foreach语句时,应用程序抛出异常。

Exception in thread "Thread-39" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at pl.mosek.MyPanel2$ColissionDetector.run(GUI.java:421)
at java.lang.Thread.run(Unknown Source)

当我使用经典for语句时,问题会神奇地消失。 有人可以解释我为什么会这样吗?

CODE:

@Override
    public void run() {

        while (true) {
            if (ship.getBullets().isEmpty() == false
                    && monsters.isEmpty() == false) {

                semaphoreLock(semaphoreBullet);

                for (Bullet i : ship.getBullets()) {
                    if (i.isDestroyed() != true) {

                        semaphoreLock(semaphoreMonster);

                        for (Enemy j : monsters) {
                            if (i.getBounds()
                                    .intersects(j.getBounds())
                                    &&j.isDestroyed() != true) {
                                i.setDestroyed(true);
                                i.setVisible(false);

                                j.setDestroyed(true);
                                j.setVisible(false);
                            }
                        }
                    }
                    semaphoreRelease(semaphoreMonster);
                }
                semaphoreRelease(semaphoreBullet);

            }
            try {
                Thread.sleep(25);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

如果我将foreach切换为for个,那么一切正常。

2 个答案:

答案 0 :(得分:3)

使用标准for循环,您可以通过get()访问列表中的元素,并(可能)通过set()设置它们。这些方法无法检测并发修改。但是,对于for-each循环,您实际上使用的是Iterator方法返回的iterator() does check for concurrent modification。因此存在差异。

for-each循环

for (Element e : list) {
    ...
}

实际上变成了:

for (Iterator<Element> iter = list.iterator(); iter.hasNext();) {
    Element e = iter.next();
    ...
}

答案 1 :(得分:1)

虽然有些existing answers可能会解释您可以做些什么来使您的代码正常运行,但他们无法准确解释出现了什么问题以及原因。

特别是,foreach语法通过ArrayList#iterator()使用迭代器,docs for ArrayList说:

  

此类的iteratorlistIterator方法返回的迭代器是 fail-fast :如果在创建迭代器后的任何时候对列表进行结构修改,则任何除了通过迭代器自己的removeadd方法之外,迭代器将抛出ConcurrentModificationException。因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来不确定的时间冒着任意的,非确定性行为的风险。