0

So I'm making a game and every 5 seconds there must spawn an enemy, know when I run my application it throws an exception 'ConcurrentModificationException'. This is a part of my code:

private void tick() {

    exec.scheduleAtFixedRate(new Runnable() {
          @Override
          public void run() {
              enemyY = enemyYRand.nextInt(6);
              enemy.add(new Enemy(enemyY, 10, enemyImg));
          }
    }, 0, 5, TimeUnit.SECONDS);

    if (player.y > getHeight() - playerImg.getHeight(null)) {
        player.setY(-10);
    }
    if (player.y < 0) {
        player.setY(+10);
    }
}

public void paintComponent(Graphics g) {
    super.paintComponent(g);
    for(Enemy enemys : enemy) {
        enemys.render(g);
    }
    player.render(g);
}

First the tick method get's called then paintComponent method.

This is the output:

Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    at _47b3n.spaceinvaders.framework.Main.paintComponent(Main.java:141)
    at javax.swing.JComponent.paint(JComponent.java:1053)
    at javax.swing.JComponent.paintToOffscreen(JComponent.java:5223)
    at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:290)
    at javax.swing.RepaintManager.paint(RepaintManager.java:1265)
    at javax.swing.JComponent._paintImmediately(JComponent.java:5171)
    at javax.swing.JComponent.paintImmediately(JComponent.java:4982)
    at javax.swing.RepaintManager$4.run(RepaintManager.java:824)
    at javax.swing.RepaintManager$4.run(RepaintManager.java:807)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:807)
    at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:782)
    at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:731)
    at javax.swing.RepaintManager.access$1300(RepaintManager.java:64)
    at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1720)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:744)
    at java.awt.EventQueue.access$400(EventQueue.java:97)
    at java.awt.EventQueue$3.run(EventQueue.java:697)
    at java.awt.EventQueue$3.run(EventQueue.java:691)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:75)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:714)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
6
  • 1
    can you post the stacktrace? By the way, I suggest you reading this: docs.oracle.com/javase/6/docs/api/java/util/… Commented Jan 28, 2016 at 19:41
  • @Pshemo Thanks, edited it Commented Jan 28, 2016 at 19:45
  • Can you tell us where you are calling paintComponent? Is it your own method? Commented Jan 28, 2016 at 19:51
  • ConcurrentModificationExceptions can be associated with any modification to a collection, additions as well as removals. Commented Jan 28, 2016 at 19:53
  • @svasa paintComponent is the method you override in AWT/Swing to paint your own components. Commented Jan 28, 2016 at 19:54

1 Answer 1

3

It appears that you have 2 threads each operating on an ArrayList at the same time.

One of them is in the event dispatch thread, where paintComponent is called. You are using an enhanced for loop, which uses an Iterator internally. This iterator is what is throwing the ConcurrentModificationException.

You are modifying the ArrayList in the tick method, in some other thread, when you call enemy.add(new Enemy(enemyY, 10, enemyImg));.

The Iterator noticed that the ArrayList was modified and threw the exception. When you are displaying the enemies, it is necessary to have a consistent view of your ArrayList.

Synchronize access to this ArrayList on some object (maybe even enemy itself) by enclosing read and write operations on this ArrayList in synchronized blocks. That means that only one of these blocks can be executing at the same time.

synchronized (enemy) {
    enemy.add(new Enemy(enemyY, 10, enemyImg));
}

and

synchronized (enemy) {
    for(Enemy enemys : enemy) {
        enemys.render(g);
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Other options for completeness: use a data structure that is inherently thread-safe, such as CopyOnWriteArrayList or ConcurrentSkipListSet. Or wrap your list using Collections.synchronizedList.
Thanks a lot for the answer!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.