Concurrent Modification Exception

Arbon

Bekanntes Mitglied
Hallo!

Ich bastle gerade an einer einfache Spieleengine, bekomme jedoch bei einem Testspiel in scheinbar unregelmäßigen Abstände eine Concurrent Modification Exception geworfen in der Spielschleife.

Meine Spielschleife sieht so aus:

Java:
public void run() {
		while (gameRunning) {
			calculateDelta();

			Graphics2D g = buffer.createGraphics();
			g.clearRect(0, 0, getWidth(), getHeight());
			g.drawString("FPS " + fps, 0, 20);

			for (GameObject o : gameList) {
				if (o instanceof Logicable)
					((Logicable) o).doLogic(delta);
				if (o instanceof Movable)
					((Movable) o).move(delta);
				o.draw(g);
			}

			g.dispose();
			g = null;
			getGraphics().drawImage(buffer, 0, 0, null);
			try {
				Thread.sleep(sleepTime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

Es passiert oft, dass Objekte wie Projektile sich aus der Spielschleife löschen, wenn sie z.B. auf ein Ziel getroffen haben. Dies Funktioniert in der doLogic Methode. Es wäre nun klar, wenn eine solche Exception geworfen wird, da die Liste ja während der Iteration geändert wird. Dies habe ich in meiner GameList (eine eigene Klasse) eigendlich berücksichtigt, die zu löschenden oder hinzuzufügenden Objekte werden vorher zwischengespeichert und vor der Zurückgabe des Iterators wird die eigentliche Liste dann abgeglichen:

Java:
public class GameList implements Iterable<GameObject> {

	private ArrayList<GameObject> addList = new ArrayList<GameObject>();
	private ArrayList<GameObject> removeList = new ArrayList<GameObject>();
	private ArrayList<GameObject> gameList = new ArrayList<GameObject>();

	public boolean add(GameObject go) {
		return addList.add(go);
	}

	public boolean remove(GameObject go) {
		return removeList.add(go);
	}

	@Override
	public Iterator<GameObject> iterator() {
		gameList.removeAll(removeList);
		removeList.clear();
		gameList.addAll(addList);
		addList.clear();
		return gameList.iterator();
	}

}

Dies scheint auch zu funktionieren, ab und zu werden jedoch dennoch die Exceptions geworfen und einen wirklichen Grund konnte ich bisher noch nicht finden. Interessant ist auch, dass sie scheinbar immer aus anderen Threads geworfen werden, ich kann mir allerdings nicht erklären wo diese Threads herkommen:

Java:
Exception in thread "Thread-3" java.util.ConcurrentModificationException
	at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
	at java.util.AbstractList$Itr.next(AbstractList.java:343)
	at armEngine.Game.run(Game.java:60)
	at java.lang.Thread.run(Thread.java:619)

Exception in thread "Thread-5" java.util.ConcurrentModificationException
...

Exception in thread "Thread-6" java.util.ConcurrentModificationException
...

Exception in thread "Thread-7" java.util.ConcurrentModificationException
...

In meinem Programm sind außer der Spielschleife eigendlich keine anderen Threads vorhanden.

mfg
 
S

SlaterB

Gast
tja, das passt zusammen, wenn nur diese Stelle auf den Iterator zugreift, dann kann es eigentlich nur eine Exception geben, wenn mehrere Threads gleichzeitig diese Aktion durchführen, also mehrere Spieleengine gleichzeitig laufen,
die dann allerdings auf dasselbe gameList-Objekt zugreifen müßten, was wieder unwahrscheinlicher ist, oder ist eine statische Variable im Spiel?

-------

wie in einem anderen Thread schon geschrieben:
http://www.java-forum.org/allgemeine-java-themen/93995-fehler-concurrentmodificationexception.html

baue Logging ein, in diesem Fall vielleicht nicht ganz so schwer,
zu Beginn der Methode iterator()
System.out.println("Iterator angefordert von "+Thread.currentThread().getName());

in der gameRunning-Schleife nach Ende der Iterator-Schleife
System.out.println("Iterator fertig von "+Thread.currentThread().getName());
usw.
evtl. hashCode() des GameList-Objektes mitausgeben, falls es davon doch mehrere geben kann
 

Arbon

Bekanntes Mitglied
So nach langer Fehlersuche habe ich den Übeltäter gefunden:

Ein Spielelement hat sobald es mit dem Spieler kollidiert ist automatisch eine loose-Methode aufgerufen, in welcher in den GameThread gestoppt habe. Durch das Join wartet die Methode dann darauf, dass das Spiel beendet wird. Dadurch, dass ich die Methode allerdings im selben Thread aufgerufen habe, bleibt er beim join hängen und das Spiel wird nie beendet. Vorher hatte ich das join noch nicht, da hatte dies den Effekt dass parallel dazu ein neuer Thread gestartet wurde, was ab und zu eine Concurrent Modification Exception ausgelöst hat.

Habe jetzt eine Art GameControlQueue, in welcher solche Methoden ausgeführt werden könnnen.
 

Steev

Bekanntes Mitglied
Hi,

die Exception kann aber auch durch dieses Konstrukt im zusammenhang mit mehreren Threads oder zu kurzen sleeps auftreten.
[Java]for (GameObject o : gameList) {
if (o instanceof Logicable)
((Logicable) o).doLogic(delta);
if (o instanceof Movable)
((Movable) o).move(delta);
o.draw(g);
}
[/Java]

Wenn du das ganze wie folgt an den entsprechenden Stellen abänderst, dann sollte der Fehler an den Stellen nicht mehr auftreten.

[Java]
GameObject o = null;
for (int i = 0; i < gameList.size(); i++) {
o = gameList.get(i);
if (o instanceof Logicable)
((Logicable) o).doLogic(delta);
if (o instanceof Movable)
((Movable) o).move(delta);
o.draw(g);
}
[/Java]

Gruß
Steev
 

Ähnliche Java Themen


Oben