0

So i'm trying to create simple gravity using LWJGL, but the application randomly crashes with the java.util.ConcurrentModificationExceptionexception. The strange thing is that is does not always happen at the same time. Sometimes it crashes instantly but other times it runs fine for 10 minutes before crashing.

Main game class:

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();
}

Block class:

/** 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();
        }
    }
}

The stack trace is the following:

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)

With (Game.java:34) being this line:

b.update();

And (Block.java:26) being:

for(Block b : Game.blocks)

If you need the full code, it's available on Github

Snakybo
  • 429
  • 2
  • 6
  • 17
  • Also, according to the Oracle Docs it mostly happens when using multithreading but i'm not multithreading here. – Snakybo May 04 '13 at 12:17

1 Answers1

4

You are multithreading. The TimerTask runs on a separate thread.

What happens is this: the spawnBlock method that is being called on the timer task thread modifies the blocks list(adds one to the list). On the main thread, the update method is called, in which the code iterates over the blocks list.

Because a block is added to the blocks list during that iteration(during the spawnblock method execution on the other thread), you get the concurrentModificationException.

Replacing "for(Block b : blocks)" by "for(Block b : new ArrayList(blocks))" is a very simple but not so performant solution: since you always iterate over a new copy, you can modify the original list as much as you want.

A better solution is probably to start making your methods synchronized or rethink your design, like wrapping the blocks list in a synchronized wrapper.

Integrating Stuff
  • 5,253
  • 2
  • 33
  • 39
  • Okay, didn't know the TimerTask runs on a seperate thread, thanks for the info i'll have to look into that synchronized wrapper, but for now `for(Block b : new ArrayList(blocks))` seems to have fixed it. Thanks – Snakybo May 04 '13 at 12:45