Frage von Bohne999, 47

Wieso funktioniert die if-Abfrage nicht korrekt (Java Multithreading)?

Ich bin gerade dran ein kleines Spiel zu entwickeln ( Java, JavaFX ). Ich habe 2 Threads, einen der für das Spiel zuständig ist und einen der den Spieler steuert.

Problem: Der Game Thread soll bisher nur überprüfen, ob der Spieler bei Y = 300 oder weiter unten ist. Dann soll der PlayerThread warten, sodass die move() Methode des Spielers nicht mehr aufgerufen wird. Mithilfe der Maus kann man die Wurfparabel neu definieren und den Ball erneut schießen indem ich playerThread.notify aufrufe. Das alles funktioniert. Nur der Spieler stoppt nicht bei 300 sondern immer unterschiedlich. Ausgabe des Punktes wo der Spieler stoppt (Mehrere Schüsse): X: 108.0, Y: 460.90 X: 108.0, Y: 460.90 X: 365.96, Y: 338.31 X: 634.35, Y: 356.10 X: 911.82, Y: 347.38 X: 301.65, Y: 330.01 X: 371.34, Y: 313.26 X: 296.21, Y: 422.00 X: 275.30, Y: 337.20 X: 320.87, Y: 300.04 X: 517.99, Y: 320.52

Findet jemand einen Fehler?

Hier ist der Code: private void createPlayerThread(){

    Task task = new Task() {
        @Override
        protected Object call() throws Exception {
            System.out.println("Starting Player Thread...");
            while (App.isRunning()){
                    player.move();
            }

            return null;
        }
    };

    playerThread = new Thread(task, "Player Thread");
    playerThread.start();

}

private void createGameThread(){

    Task task = new Task() {
        @Override
        protected Object call() throws Exception {
            System.out.println("Starting Game Thread...");

            while (App.isRunning()) {
                synchronized (player) {
                    if (player.getLayoutY() > 300) {
                        System.out.println(new Point(player.getLayoutX(),player.getLayoutY()).toString());
                        synchronized (playerThread) {
                            playerThread.wait();
                        }
                    }
                }

            }
            return null;
        }

    };
    gameThread = new Thread(task, "Game Thread");
    gameThread.start();
} 
Antwort
von PeterKremsner, 29

Du solltest in den while Schleifen der Threads sleeps oder Thread yields einbauen, sonst verbrauchen diese ziemlich viel CPU Zeit, dadurch kann es passieren, dass das Programm ewig in dem einen Thread festhängt weil er einfach den Prozessor nicht freigibt.

In dem Fall würde ich auch nicht mit synchronize Snychronisieren sondern explizit mit einem Mutex.

Zudem lass nicht den einen Thread den anderen Starten, wenn das immer so ist, starte die Threads beide hintereinander von der main Funktion aus.

Generell gilt möglichst wenig geteilte Ressourcen zwischen Threads verwenden.

Expertenantwort
von KnusperPudding, Community-Experte für Java, 15

Findet jemand einen Fehler?

So wirklich ein "Fehler" ist das nicht.

Das Problem besteht in einer 'falschen Anwendung':

Der Thread, der die Koordinaten hält und diese Verändert zum einen, und ein zweiter der diese Werte prüft.

Da Threads ja parallel laufen wäre es glück wenn beim Abfragen exakt der wert von 300+ raus kommen würde.

Wäre es eine Option wenn der Spieler-Thread einfach dem Game-Thread mitteilen könnte: "300 Überschritten?"

Kommentar von Bohne999 ,

Also später soll noch eine Kollisionsabfrage mit einem Polygon folgen. Die 300+ dienen mir nur gerade um den Spieler komplett zu implementieren. Aber du meinst, dass ich die Kollisionsabfrage im Spielerthread durchführe? 

Kommentar von KnusperPudding ,

Ja, genau. Dem Game-Thread teilst du dann nur das Ergebnis der Kollision mit: true/false.

Kommentar von Bohne999 ,

Hab das ganze gerade ausprobiert. Funktioniert fast perfekt, muss jetzt nur noch überprüfen ob der Funktionswert über 300 ist weil und dann den Spieler auf 300 setzten weil Y Pos + Funktionswert ist ja nicht immer = 300 :D Naja Danke für deine Hilfe :)

Kommentar von KnusperPudding ,

Gerne. Freut mich wenn ich helfen konnte

Antwort
von NeoExacun, 28

Du kannst bei Multithreading eben nie garantieren, wann welcher Thread ausgeführt. Der GameThread wird irgendwann aktiviert, was der PlayerThread in dieser Zeit macht, kann er nicht beeinflussen.

Keine passende Antwort gefunden?

Fragen Sie die Community