Hallo liebe Gemeinde,
habe das Spiel Snake nachprogrammiert. Damit die Schlange nach jedem Fressen Aufsammeln wachsen kann, wird in eine ArrayList ein neues Schwanzteil hinzugefügt. Dort werden auch die Koordinaten der Schwänze festgehalten. Es gibt - glaube ich- drei Threads, die auf diese ArrayList zugreifen. Einmal meine GameClock - eigenes Thread -, die nach einem Fressen die Methode addTail aufruft. Dann das Haupthread, die x- und y- Koordinate für die Bewegung der Schlange anpasst. Und zum Schluss mein Draw Thread für das Zeichnen in meinem Fenster. Meine Draw-Klasse erweitert JLabel und überschreibt die paintComponent(Graphics g) Methode.
So, ich glaube die o. g. Exception kommt, weil mind. 2 Threads zur gleichen Zeit auf die ArrayList zugreifen wollen. Das geht wohl nicht. Die Draw-Klasse hat repaint(), so dass sie vielleicht 1000 mal in der Sekunde ausgeführt wird und die GameClock stoppt alle 200 Milisekunden. Mein HauptThread greift auf die ArrayList per Aufruf, so dass es nicht so häufig passiert. Ich vermute, dass der Fehler deswegen meistens ab 30 Aufsammeln auftritt.
Das ist der gesamte Fehlerlauf:
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1012)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:966)
at gui.MyDraw.paintComponent(MyDraw.java:40)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1074)
at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083)
at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5255)
at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedFPScales(RepaintManager.java:1707)
at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1616)
at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1556)
at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1323)
at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5203)
at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5013)
at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:865)
at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:848)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:848)
at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:823)
at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:772)
at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1884)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:316)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Ich habe versucht in meiner MyDras-Klasse (oben fett markiert), folgende synchronisation zu machen:
Trotzdem ist der Fehler aufgetaucht. Wie kann ich meine Synchronisation so setzen, dass der Fehler nicht mehr passiert?
Oder soll ich in der MyDraw-Klasse eine neue Array-List erstellen, die eine Kopie der originalen ist? D.h. die x- und y-Werte werden in der Originalen gesetzt, die Kopie-ArrayList holt sich die Werte von der originalen, und die for-Schleife zum Zeichnen greift auf die Kopie, dass es ein gleichzeitiger Doppelaufruf einer ArrayList nicht geben kann.
Oder liege ich mit meiner Vermutzung absolut falsch, dass der Fehler wegen gleichzeitigem Zugriff auf die ArrayList MySnake.tails entseht?
Lieben Dank
)
habe das Spiel Snake nachprogrammiert. Damit die Schlange nach jedem Fressen Aufsammeln wachsen kann, wird in eine ArrayList ein neues Schwanzteil hinzugefügt. Dort werden auch die Koordinaten der Schwänze festgehalten. Es gibt - glaube ich- drei Threads, die auf diese ArrayList zugreifen. Einmal meine GameClock - eigenes Thread -, die nach einem Fressen die Methode addTail aufruft. Dann das Haupthread, die x- und y- Koordinate für die Bewegung der Schlange anpasst. Und zum Schluss mein Draw Thread für das Zeichnen in meinem Fenster. Meine Draw-Klasse erweitert JLabel und überschreibt die paintComponent(Graphics g) Methode.
So, ich glaube die o. g. Exception kommt, weil mind. 2 Threads zur gleichen Zeit auf die ArrayList zugreifen wollen. Das geht wohl nicht. Die Draw-Klasse hat repaint(), so dass sie vielleicht 1000 mal in der Sekunde ausgeführt wird und die GameClock stoppt alle 200 Milisekunden. Mein HauptThread greift auf die ArrayList per Aufruf, so dass es nicht so häufig passiert. Ich vermute, dass der Fehler deswegen meistens ab 30 Aufsammeln auftritt.
Das ist der gesamte Fehlerlauf:
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1012)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:966)
at gui.MyDraw.paintComponent(MyDraw.java:40)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1074)
at java.desktop/javax.swing.JComponent.paintChildren(JComponent.java:907)
at java.desktop/javax.swing.JComponent.paint(JComponent.java:1083)
at java.desktop/javax.swing.JComponent.paintToOffscreen(JComponent.java:5255)
at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedFPScales(RepaintManager.java:1707)
at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1616)
at java.desktop/javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1556)
at java.desktop/javax.swing.RepaintManager.paint(RepaintManager.java:1323)
at java.desktop/javax.swing.JComponent._paintImmediately(JComponent.java:5203)
at java.desktop/javax.swing.JComponent.paintImmediately(JComponent.java:5013)
at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:865)
at java.desktop/javax.swing.RepaintManager$4.run(RepaintManager.java:848)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:848)
at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:823)
at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:772)
at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1884)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:316)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Ich habe versucht in meiner MyDras-Klasse (oben fett markiert), folgende synchronisation zu machen:
Java:
g.setColor(new Color(51,204,51));
synchronized (MySnake.tails) {
for (MyTail t : MySnake.tails) {
g.fillRect(MyKoordinate.xPoint(t.getX()), MyKoordinate.yPoint(t.getY()), MyFrame.feldGr,
MyFrame.feldGr);
}
}
Trotzdem ist der Fehler aufgetaucht. Wie kann ich meine Synchronisation so setzen, dass der Fehler nicht mehr passiert?
Oder soll ich in der MyDraw-Klasse eine neue Array-List erstellen, die eine Kopie der originalen ist? D.h. die x- und y-Werte werden in der Originalen gesetzt, die Kopie-ArrayList holt sich die Werte von der originalen, und die for-Schleife zum Zeichnen greift auf die Kopie, dass es ein gleichzeitiger Doppelaufruf einer ArrayList nicht geben kann.
Oder liege ich mit meiner Vermutzung absolut falsch, dass der Fehler wegen gleichzeitigem Zugriff auf die ArrayList MySnake.tails entseht?
Lieben Dank