【问题标题】:ConcurrentModificationException but not removing anything from ArrayListConcurrentModificationException 但未从 ArrayList 中删除任何内容
【发布时间】:2016-01-28 19:38:19
【问题描述】:

所以我正在制作一个游戏,每 5 秒必须产生一个敌人,知道当我运行我的应用程序时它会抛出异常“ConcurrentModificationException”。 这是我的代码的一部分:

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

首先调用tick方法,然后调用paintComponent方法。

这是输出:

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)

【问题讨论】:

  • 你能发布堆栈跟踪吗?顺便说一句,我建议您阅读以下内容:docs.oracle.com/javase/6/docs/api/java/util/…
  • @Pshemo 谢谢,已编辑
  • 你能告诉我们你在哪里调用paintComponent吗?是你自己的方法吗?
  • ConcurrentModificationExceptions 可以与对集合的任何修改、添加和删除相关联。
  • @svasa paintComponent 是您在 AWT/Swing 中覆盖以绘制您自己的组件的方法。

标签: java arrays arraylist exception-handling


【解决方案1】:

您似乎有 2 个线程,每个线程同时在 ArrayList 上运行。

其中一个在事件调度线程中,其中调用了paintComponent。您正在使用增强的 for 循环,它在内部使用 Iterator。这个迭代器就是抛出ConcurrentModificationException

当您调用enemy.add(new Enemy(enemyY, 10, enemyImg)); 时,您正在修改tick 方法中的ArrayList,在其他线程中。

Iterator 注意到 ArrayList 被修改并抛出异常。当你显示敌人时,你的ArrayList有一个一致的视图是必要的。

通过将对此ArrayList 的读写操作封闭在synchronized 块中,同步访问某个对象(甚至可能是enemy 本身)上的此ArrayList。这意味着只能同时执行这些块中的一个。

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

synchronized (enemy) {
    for(Enemy enemys : enemy) {
        enemys.render(g);
    }
}

【讨论】:

  • 其他完整性选项:使用本质上是线程安全的数据结构,例如CopyOnWriteArrayListConcurrentSkipListSet。或使用Collections.synchronizedList 包装您的列表。
  • 非常感谢您的回答!
猜你喜欢
  • 2015-01-10
  • 2014-06-03
  • 1970-01-01
  • 2013-12-14
  • 2013-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-12
相关资源
最近更新 更多