IronRabbit
IronRabbit

Reputation: 185

Object state modification during thread execution

I'm working on a little game (bomberman), using javafx. Basically, I have players which can plant bomb. The bomb has a duration (1500ms before explosion, for example).

So, when my player plant a bomb, I start a thread in the bomb, using a Thread.sleep(ms), and right after I notify the player that the bomb has exploded.

Thing is, my player can drop his bomb then move... But when the bomb explodes, it notify the instance of the player with the coordinate when the bomb was planted...

For example, if my player is in [2;2], plant a bomb, then move to [2;4], then the bomb explodes, my player goes back to [2;2]...

Anyone knows how could I actualize the instance of player my bomb is pointing to ... ?

Here's a sample of code :

public class Player{
    public void putBomb(){
        listBomb.add(new Bomb(this));
    }

    public void refresh(){
        System.out.println(xCoordinate+" "+yCoordinate);
    }

}

public class Bomb{
    public Bomb(Player p){
        observer=p;

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1500);
                    notify();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public void sendNotification(){
        observer.refresh();
    }

}

Upvotes: 0

Views: 190

Answers (2)

jewelsea
jewelsea

Reputation: 159546

As your question is JavaFX specific, the recommendations on how to do this vary from a non-GUI Java program (because JavaFX has in-built concurrency assistance and a single-threaded application programming model).

You don't need another thread, you can use a PauseTransition.

public class Bomb{
    public Bomb(final Player player){
        PauseTransition pause = new PauseTransition(Duration.seconds(1.5));
        pause.setOnFinished(event -> player.refresh());
        pause.play();
    }
);

If for some reason you didn't wish to use a transition and you want to use your own threading, then you should look use JavaFX concurrency utilities such as Task.

If you didn't want to use a Task, then you can still create your own thread or runnable, but ensure that any callbacks are made using Platform.runLater(). For example:

public class Bomb{
    public Bomb(final Player player){
        new Thread(() -> {
                try {
                    Thread.sleep(1500);
                    Platform.runLater(() -> player.refresh());
                } catch (InterruptedException e) {}
            }
        }).start();
    }
}

Of the different approaches, I recommend the PauseTransition over the others as then you don't need to deal with concurrency details such as threading, which are easy to get wrong.

Upvotes: 1

Solomon Slow
Solomon Slow

Reputation: 27190

Your run method calls [this.]notify() without being synchronized on this. I would expect it to always throw an IllegalMonitorStateException.

Also, it's almost always a mistake to call notify() without also setting some variable that other threads can examine. The problem with notify() is that it does not do anything at all unless some other thread happens to be in a wait() call for the same object. Without proper synchronization, you have no way to guarantee that that will be true.

There's only one right way to use wait() and notify(), and that's in a design pattern that Oracle calls a guarded block. https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

Upvotes: 0

Related Questions