0

I'm new with Java threads and I am having a few problems. I'm trying to make a simple ludo game, where each player makes their turn in a new thread. While one player is performing their turn the other threads must wait() until notified and the next player will start his turn. These threads must be synchronised so that only one thread can manipulate shared data at one time. I've implemented some basic logic but can't decide where to create the threads and if the thread logic I've implemented will work. Any help is appreciated!

Edit: I remade some parts of the code, but now I get "current thread is not owner" error after the first call of finishTurn().

Code:

Main.java:

public class Main {
    public static void main(String[] args) {
        Game game = new Game();
        game.init();
        game.run();
    }
}

Game.java:

public class Game implements Runnable {
    private List<Player> players;
    private List<Player> fields;
    private int players_finished;
    private Player winner;

    public Game() {
        this.players = new ArrayList<>();
        this.fields = new ArrayList<>();
        this.players_finished = 0;
        this.winner = null;
    }

    public void init()
    {
        System.out.println("Game has started!");
        players.add(new Player("Magnum", this));
        players.add(new Player("Felix", this));
        players.add(new Player("Alex", this));
        players.add(new Player("Sandra", this));

        for(int i = 0; i < 20; i++) {
            fields.add(i, null);
        }

        for(int i = 0; i < 20; i++) { // put players' 5 fields away from each other
            if(i % 5 == 0)
            {
                fields.set(i, players.get((int)i / 5));
            }
        }
    }

    @Override
    public void run()
    {
        List<Thread> threads = new ArrayList<>();
        for(int i = 0; i < 4; i++) {
            threads.add(new Thread(players.get(i)));
            threads.get(i).start();
        }
        System.out.println("Game has started!");

        finishTurn(players.get(3));
    }

    void finishTurn(Player player)
    {
        System.out.println(player + " has finished his turn!");
        int i;
        for(i = 0; i < players.size(); i++) {
            if(players.get(i) == player) {
                break;
            }
        }
        if(i == (players.size() - 1)) {
            players.get(0).notify();
        }
        else {
            players.get(i+1).notify();
        }
    }
}

Player.java:

public class Player implements Runnable {
    String name;
    Game game;

    public Player(String name, Game game) {
        this.name = name;
        this.game = game;
    }

    @Override
    public void run() {
        synchronized (this) {
            try {
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        System.out.println("Player's turn has been started!");
        // do other stuff
        game.finishTurn(this);
    }

    @Override
    public String toString() {
        return name;
    }
}
Deutrys
  • 15
  • 5
  • You need to use a [guarded wait](https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html) in a loop, along with a condition that indicates which player the notification is for (or, equivalently, which is to play next) to avoid problems with [spurious wake-ups](https://stackoverflow.com/questions/1050592/do-spurious-wakeups-in-java-actually-happen). But more importantly, if only one player can act, what is the point of using threads at all? – David Conrad Jun 15 '22 at 22:16
  • @DavidConrad Yeah there isn't any point in this case I'm just trying to learn and practice threads. I remade some parts of the code and now it starts running but crashes after the first call of finishTurn() with the error: "current thread is not owner". – Deutrys Jun 16 '22 at 08:53
  • As @David Conrad said, what's the point of using Threads? If you want to use Threads, use them correctly, as in creating multiple asynchronous independent tasks. In that case, use an ExecutorService instead. – Gilbert Le Blanc Jun 16 '22 at 09:42
  • Both `wait()` and `notify()` can only be called while holding a lock on the object's monitor. As the [notify documentation](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Object.html#notify()) says, "This method should only be called by a thread that is the owner of this object's monitor." – David Conrad Jun 16 '22 at 13:17

0 Answers0