未被修改的列表上的ConcurrentModificationException

时间:2017-03-27 13:24:30

标签: java

编辑:问题解决了!

感谢大家的帮助。我知道我需要同步一套,只是无法解决哪一个问题。相当令人尴尬的是,我已经同步了正确的一个,但没有将同步集分配给变量。哦,我们生活和学习。

我对Java比较新,这是我的第一个个人项目。我试图建立一个简单的2d平台游戏,并且有一个我无法弄清楚的ConcurrentModificationException弹出窗口。我已经搜索了一段时间,但找不到任何像我一样的问题的人。问题出现在以下方法中:

public Set<Platform> change(Set<Platform> platforms)
{
    Set<Platform> viewSet = new HashSet<Platform>();
    Point abPos = ball.getAbPos();
    int viewWidth, viewHeight, viewXPos, viewYPos;
    for (Platform p : platforms) {
        if (null != p.getType()) {
            switch (p.getType()) {
                case PLATFORM:{
                    viewWidth = p.getWidth() * xRatio;
                    viewHeight = p.getHeight() * yRatio;
                    viewXPos = (p.getX() - ball.getX()) * xRatio + abPos.x;
                    viewYPos = (p.getY() - ball.getY()) * yRatio + abPos.y;
                    viewSet.add(new Platform(viewXPos, viewYPos, viewWidth, viewHeight, p.getType()));
                    break;
                }
                case WALL:{
                    viewWidth = p.getWidth() * xRatio;
                    viewHeight = p.getHeight() * yRatio;
                    viewXPos = (p.getX() - ball.getX()) * xRatio + abPos.x;
                    viewYPos = (p.getY() - ball.getY()) * yRatio + abPos.y;
                    viewSet.add(new Platform(viewXPos, viewYPos, viewWidth, viewHeight, p.getType()));
                    break;
                }
                case DROP:
                    break;
                default:
                    break;
            }
        } else {
        }
    }
    return viewSet;
}

该方法在JPanel的paintComponent()方法中调用,来自我创建的Camera对象,其作用是获取方法传递给它的对象列表,并调整它们以进行绘制。这在每次游戏迭代中发生一次。传递给方法的对象列表是在每次迭代时从玩家的设定距离收集的,并且返回的已调整大小的对象列表由paintComponent()方法绘制。

问题是,当我启动for循环迭代传递给方法的对象列表时,change()方法通常会抛出ConcurrentModificationException,尽管不是每次迭代。我真的无法解决为什么因为抛出异常的列表没有以任何方式修改。任何帮助都会非常感激,因为我开始拔头发。我尝试过同步各种方法或集合,但这似乎没有任何区别,除了有时使代码滞后。

我得到的错误如下:

    Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429)
at java.util.HashMap$KeyIterator.next(HashMap.java:1453)
at mygame_2.Camera.change(Camera.java:39)
at mygame_2.Game2Window$DrawingPanel.paintComponent(Game2Window.java:237)
at javax.swing.JComponent.paint(JComponent.java:1056)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5217)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
at javax.swing.JComponent.paint(JComponent.java:1042)
at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:79)
at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:116)
at java.awt.Container.paint(Container.java:1975)
at java.awt.Window.paint(Window.java:3912)
at javax.swing.RepaintManager$4.run(RepaintManager.java:842)
at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
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)

如果代码或此问题混乱,请道歉。

2 个答案:

答案 0 :(得分:0)

变量viewSet是本地的,因此不会抛出异常,因此消除不可能,唯一可以引发此异常的集合就是您传递的异常。

你传入的Set必须来自某个地方,必须要填补它。由于paintComponent发生在Swing渲染线程上,所以冲突可能是您正在读取Swing线程上的Set,同时在另一个线程上修改它。

如果您在synchronized块内对此集进行了修改,并且在Set块中遍历了synchronized,则问题应该会消失:

synchronized (set) {
    // read/write here
}

在两种情况下,变量set都应该是相同的。

答案 1 :(得分:0)

我在使用for-each循环时只得到了这个错误。尝试切换for-each循环以获得传统的for循环。它应该摆脱错误。