# Thread.sleep() problem



## MarlonD (23. Jul 2008)

Hallo!

Bei der Umsetzung eines Echtzeit-Browsergames (Applet) mache ich die negative Entdeckung, dass das gleiche Programm mit gleichen Parametern, Konstanten, etc... ab und zu ein wenig anders läuft. Diese Asynchronität rührt aber nicht von einer unterschiedlichen Java-Version oder Rechnersystems.
Ich habe einiges getestet und wie es ausschaut führt kein Fehler zu dem Problem. (Dieser könnte ja die laufende Schleife abbrechen und weitere Programmteile ignorieren...)

Daher glaube ich, dass es am Thread liegt.
Für das Programm verwende ich allerdings bloss einen Thread, der für die gesamte Logik verantwortlich ist.
Ich bin jetzt kein Guru was Threads anbelangt, aber trotzdem bin ich mir relativ sicher, dass sich ein und der selbe Thread nicht "selber überspringen" kann.
Oder täusche ich mich da? Ist es evtl. möglich, dass nach Ablauf der Zeit in "Thread.sleep(zeit)" der Thread erneut gestartet wird, oder läuft der Thread wie erwartet zu Ende?

Ich gehe jetzt mal davon aus, dass der Thread zusätzlich zur Ausführzeit die Zeit "zeit" wartet.
Wer kann mich aufklären/mir helfen?

Danke im Vorraus!
Marlon


----------



## madboy (23. Jul 2008)

Thread.sleep() legt den Thread schlafen und so bald die Zeit abgelaufen ist, gehts im Programmfluß hinter Thread.sleep() weiter.

Wenn du schreibst "ab und zu ein wenig anders läuft", sieht das für mich nach einem Synchronisationsproblem zwischen verschiedenen Threads aus. Aber ohne weitere Informationen lässt sich nicht viel sagen.

Beschreibe doch bitte, was genau du haben willst und was genau passiert. Am besten mit einem minimalen, lauffähigen Beispiel, das das Problem demonstriert.


----------



## Marco13 (23. Jul 2008)

_....bin ich mir relativ sicher, dass sich ein und der selbe Thread nicht "selber überspringen" kann._
Wenn du sagst, was das heißt, kann jemand das bestätigen oder verneinen.

_Ist es evtl. möglich, dass nach Ablauf der Zeit in "Thread.sleep(zeit)" der Thread erneut gestartet wird, oder läuft der Thread wie erwartet zu Ende?_
Der Thread wird von außen gestartet, wartet gegebenenfalls, wird bestenfalls von außen unterbrochen (und läuft andernfalls zuende), und kann auch nur von außen neu gestartet werden.

_Ich gehe jetzt mal davon aus, dass der Thread zusätzlich zur Ausführzeit die Zeit "zeit" wartet._
Prinzipiell ja...


----------



## MarlonD (23. Jul 2008)

Erstmal Danke für die Antworten!

Ich habe momentan keinen Zugriff zum Code, ein Posting dessen wäre wahrscheinlich sowieso viel zu verwirrend.
Ich könnte es aber mal kurz beschreiben:

Es gibt bei der Anwendung lediglich einen PaintThread (der ist fürs Zeichnen der Bilder im Applet zuständig), einen ImageLoadThread (der lädt die Bilder, die fürs Zeichnen benötigt werden) und einen LogicThread (der ist für jegliche Rechenoperationen zuständig, die den Spielablauf bestimmen).
Folglich kann logischerweise auch nur der zuletzt genannte Thread für die Asynchronität verantwortlich sein.

Der LogicThread durchläuft eine Schleife und wartet anschliessend 10 ms. Dies passiert solange, bis das Spiel vorbei ist.
Bei jedem Eintritt in diese Schleife wird eine Zählervariable um 1 inkrementiert. Diese steht also für den Zyklus, in dem sich das Programm aktuell befindet. Danach wird die gesamte Spiellogik für einen Durchlauf berechnet.

Im normalen Singleplayer Modus funktioniert das Spiel auch sehr gut und macht Spass. Im sich in der Produktion befindlichen Multiplayer Modus jedoch gibt es ab und zu diese angesprochene Problematik mit der Asynchronität.

Ich gebe in der Konsole aus, in welcher Runde was passiert und mache die Beobachtung, dass der Zyklus zwischen beiden Spielern manchmal leicht voneinander differenziert, was natürlich eine Lawine der Asynchronität hervorruft.
Hinzuzufügen wäre noch, dass ich hier von einem Rundenbasierten Modus spreche. Also wie bereits besprochen wird das gesamte Programm mit den absolut gleichen Parametern und Objekten für Spieler1 und Spieler2 ausgeführt.

Alle Fehler, die ich auffange, gebe ich in der Konsole aus, jedoch tritt keiner auf. Ich kann mir jedoch nicht vorstellen, warum der Zyklus teilweise schneller voran gezählt wird.
Deswegen meine Überlegung, dass sich der Thread "überspringt", also das quasi die Schleife vor Ablauf der Vorigen gestartet wird. Aber das kann doch eigentlich nicht sein?!?

Wo ist dann der Denkfehler? Ich persönlich tippe auf 99%, dass es was mit der Threadprogrammierung zu tun hat.

Mhhh, soweit erstmal dazu, evtl. weiss jemand weiter...

Marlon


----------



## EgonOlsen (23. Jul 2008)

Und die Spieler werden einer nach dem anderen in selben Thread bearbeitet? Oder sind das zwei getrennte?


----------



## madboy (23. Jul 2008)

Habe ich das richtig verstanden, dass wenn bei einem Spieler 9,5 ms gewartet wird und beim anderen 10,5 ms, dass dann die von dir beschriebenen Probleme auftreten können?

Falls ja: Thread.sleep() ist kein Präzisionsinstrument in dem Sinne. Das Problem ist allerdings nicht unbedingt die Java-Methode, sondern das Prinzip, nach dem (nicht realtime-)Betriebssysteme die CPU zuteilen (Stichwort scheduling). Es kann und wird durchaus vorkommen, dass nicht exakt die Zeit geschlafen wird, die bei Thread.sleep() angegeben wird.

Falls nein: ich verstehe immer noch nicht, was das Problem ist.


----------



## MarlonD (23. Jul 2008)

Es ist irrelevant wie lange gewartet wird.
Du könntest das Spiel auf einem 486 zocken und es sollte funktionieren. Es ist mir auch klar, das besonders Windows es nicht so genau nimmt mit der Systemzeit.

Es ist eine Art Challenge (Herausforderung) die ausgetragen wird.
Du forderst einen Spieler heraus, indem du deine Objekte (Türme) setzt. Dieser kann dann die Herausforderung annehmen und kontern. Hat auch er all seine Objekte platziert geht das Spiel los.
Ab jetzt ist es wie ein Film, alles wird berechnet, sollte aber immer gleich berechnet werden.
Der Herausforderer kann sich im nachhinein das ganze (den Film) nochmal ansehen.
In den meisten Fällen ist es (wir hatten 50000 Zyklen) sogar zu 100 % synchron. Aber eben nicht immer. Meistens tritt sofort am Anfang eine Asynchronität auf.

Achja, für alle Interessenten (Bilder sagen mehr als 1000 Worte):
www.towerwars.de


----------



## EgonOlsen (23. Jul 2008)

Also d.h. das läuft dann auf zwei Clients, wenn ich das richtig verstehe? Und es ist völlig Tüte, ob nun wirklich 10ms oder 20ms oder auch 10h gewartet wird, es muss nur nach 10000 Schritten der Stand der Spielwelt identisch sein...und das ist er nicht. Richtig verstanden soweit? Wenn ja, dann, da sich Treads nicht "selber überholen" können, musst du irgendein nicht-deterministisches Element haben. Machst du vielleicht implizit noch irgendwas am Stand der Welt im AWT Eventthread?
Wie genau äußert sich denn das Asynchrone?


----------



## MarlonD (24. Jul 2008)

Ja genau!
Du hast es richtig verstanden.

Aber einen AWT Eventthread habe ich nicht, oder doch?
Ich zeichne nunmal innerhalb der paint Methode, und dieses Zeichnen ist ja losgelöst vom LogicThread.
Oder meinst du die Eventlistener wie Keylistener oder Mouselistener? Nunja, das alles sollte eigentlich keine Rolle spielen.

Also wie gesagt tritt meistens am Start eine Asynchronität auf.
Ein Beispiel:
Der Pfeil des gleichen Turmes trifft bei Spieler1 7 Zyklen früher ein als bei Spieler 2.
Meistens verhällt es sich aber das ganze Spiel über (~40000 Zyklen) synchron.
Tritt aber die Asynchronität auf (was etwa bei jedem 4. Mal und dann meistens am Anfang der Fall ist) läuft das gesamte Spiel aus dem Rahmen.
Ich kann es mir nicht erklären, es werden zwar Bilder geladen am Anfang, dann aber in einem anderen Thread.

Es ist wirklich zum Verzweifeln... Nunja werde weiter testen.
Wenn einem nochwas einfällt, ich bin wirklich für alles dankbar.
Gute Nacht!
Marlon


----------



## EgonOlsen (24. Jul 2008)

MarlonD hat gesagt.:
			
		

> Aber einen AWT Eventthread habe ich nicht, oder doch?
> Ich zeichne nunmal innerhalb der paint Methode, und dieses Zeichnen ist ja losgelöst vom LogicThread.
> Oder meinst du die Eventlistener wie Keylistener oder Mouselistener? Nunja, das alles sollte eigentlich keine Rolle spielen.


Beides. Zeichnen und die Listener läuft in einem Thread, eben diesem AWT Eventthread. Ich dachte, du machst da vielleicht implizit irgendwas, was sich mit dem Logikthread beisst, wie z.B. Position des Pfeils lesen, zeichnen und Position dann wieder setzen (warum auch immer...aus versehen vielleicht)...sowas in der Art. Das würde erklären können, wieso es manchmal nicht stimmt, weil Teile der Spielwelt "von hinten" modifiziert werden.


----------



## MarlonD (24. Jul 2008)

Nein, also sowas mache ich definitiv nicht.
Ich weiss, es ist zum Haare raufen und ich werde das wohl akribisch debuggen muessen.
Danke auf jedenfall bis hierhin und wem nochwas einfaellt, der kann ja gerne schreiben.

Ansonsten: www.towerwars.de (Wenigstens funktioniert der Singleplayer)


----------

