简体   繁体   中英

ConcurrentModificationException but not removing anything from ArrayList

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)

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM