0

所以我正在尝试使用 LWJGL 创建简单的重力,但应用程序会随机崩溃,但有java.util.ConcurrentModificationException例外。奇怪的是,这并不总是同时发生。有时它会立即崩溃,但有时它会在崩溃前正常运行 10 分钟。

主要游戏类:

public static ArrayList<Block> blocks;

public Game() {
    blocks = new ArrayList<Block>();

    for(int i = 0; i < 40; i++)
        blocks.add(new BlockTest(i, 21, new float[] {0.4f, 0.6f, 0.7f}, false, 0));

    spawnTimer.scheduleAtFixedRate(new TimerTask() {
          public void run() {
              spawnBlock();
          }
    }, 1000, 1000);
}
public void update() {
    for(Block b : blocks)
        b.update();
}

块类:

/** Update block */
public void update() {
    if(hasGravity) {
        boolean colliding = false;

        for(Block b : Game.blocks)
            if(b.getBlockID() == 0) {
                if(Util.checkBlockCollision(this, b)) {
                    colliding = true;
                    setBlockID(0);
                }
            }

        if(fallDelay.over() && !colliding) {
            setBlockYPosWithoutBlockSize(y += 2);
            fallDelay.start();
        }
    }
}

堆栈跟踪如下:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at snakybo.gravitytest.block.Block.update(Block.java:26)
    at snakybo.gravitytest.Game.update(Game.java:34)
    at Main.gameLoop(Main.java:52)
    at Main.main(Main.java:21)

以 (Game.java:34) 为这一行:

b.update();

并且 (Block.java:26) 是:

for(Block b : Game.blocks)

如果你需要完整的代码,可以在Github上找到

4

1 回答 1

4

你是多线程的。TimerTask 在单独的线程上运行。

发生的事情是这样的:在计时器任务线程上调用的 spawnBlock 方法修改了块列表(将一个添加到列表中)。在主线程上,调用 update 方法,其中代码迭代块列表。

因为在该迭代期间(在另一个线程上执行 spawnblock 方法期间)将一个块添加到块列表中,所以您会收到 concurrentModificationException。

将“for(Block b : blocks)”替换为“for(Block b : new ArrayList(blocks))”是一个非常简单但性能不高的解决方案:因为您总是迭代一个新副本,您可以将原始列表修改为随心所欲。

更好的解决方案可能是开始使您的方法同步或重新考虑您的设计,例如将块列表包装在同步包装器中。

于 2013-05-04T12:28:54.733 回答