Reputation: 6852
I'm programming a simple Snake game. So, I have an update thread, executes an infinite while-loop, which updates all the GameObjects and repaints the JPanel.
// Run thread
public void run () {
try {
while (true) {
this.update();
this.getGamePanel().sceneShouldRepaint();
Thread.sleep(this.getFps());
}
}
catch (Exception e) {
JOptionPane.showMessageDialog(null, e.getMessage(), "Error", JOptionPane.OK_CANCEL_OPTION);
}
}
Now, the problem is that when I call myJFrame.repaint()
it's probably being executed in another thread. And when I paint, I obviously have to get the location of the objects, speed and so on...
I know the exception comes from paintComponent()
, because it's not being caught.
As you can see, the while loop is embedded in a try-catch.
What can I do about this?
Here's the exception:
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at ch.ilijatovilo.Scene.GameObjects.Creatures.Snake.Snake.render(Snake.java:52)
at ch.ilijatovilo.Scene.SceneHandling.Scene.renderSceneObjects(Scene.java:57)
at ch.ilijatovilo.Scene.SceneHandling.Scene.render(Scene.java:53)
at ch.ilijatovilo.Scene.SceneHandling.GamePanel.paintComponent(GamePanel.java:53)
at ch.ilijatovilo.Scene.SceneHandling.GamePanel.paint(GamePanel.java:30)
at javax.swing.JComponent._paintImmediately(JComponent.java:5106)
at javax.swing.JComponent.paintImmediately(JComponent.java:4890)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:812)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:714)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:694)
at javax.swing.RepaintManager.access$700(RepaintManager.java:41)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1672)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:702)
at java.awt.EventQueue.access$400(EventQueue.java:82)
at java.awt.EventQueue$2.run(EventQueue.java:663)
at java.awt.EventQueue$2.run(EventQueue.java:661)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:672)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Thanks for your help!
HINT
ConcurrentModificationException is being thrown if you try to access an instance at the same time from 2 different threads. That's what I've heard about it at least.
More Code
// This is the render method in the Snake class at line 50.
// So 52 is the start of the for loop
public void render(Graphics g) {
// We delegate the drawing to the body parts
for (SnakeBodyPart sbp : this.getSnakeBodyParts()) {
sbp.render(g);
}
this.getSnakeHead().render(g);
}
// And here the for loop from the Scene class
protected void renderSceneObjects (Graphics g) {
for (SceneObject so : this.getSceneObjects()) {
so.render(g);
}
}
Upvotes: 1
Views: 1956
Reputation: 203
Well CopyOnWriteArrayList is an answer. I will look after another solution when i have some time ...
Another Solution in awt - Based Application should be
EventQueue.invokeLater(new Runnable() {...});
Upvotes: 1
Reputation: 209
If you are adjusting the list in both threads you would see a problem like you mention. If you are not able to find the 'Comodification' you could lean on the java.util.concurrent libraries.
http://docs.oracle.com/javase/tutorial/essential/concurrency/collections.html
Upvotes: 0
Reputation: 533500
Most likely you are changing the details which need to be rendered in another thread which this library doesn't appear to allow (I would assume most GUI libraries do not allow this)
Whenevr you change a GUI component or something you will render you need to call SwingUtils.invokeLater() so the task will be performed in the GUI Event Thread and not concurrently in another thread.
Upvotes: 2