Search code examples
javamultithreadingjava.util.concurrent

Why Thread communication is not working in java?


I am working a small java based game, I am trying to fire missile by player-1 until player-1 doesn't miss target, once Player-1 missed target, then fire tern will move to Player-2, Player-2 will start firing until he miss his target vice versa.

Here Player-1 and Player-2 both are a Java Runnable task please find bellow code :

public class GameRender implements IGame {
    private Game game;
    private Player player1, player2;
    private Lock lock = new ReentrantLock();
    Condition notPlayer1TernCondition = lock.newCondition();
    Condition notPlayer2TernCondition = lock.newCondition();

    public GameRender(Game game, Player player1, Player player2) {
        this.game = game;
        this.player1 = player1;
        this.player2 = player2;
    }

    @Override
    public void create() {

    }

    @Override
    public void render() {
        //ExecutorService executorService = Executors.newFixedThreadPool(2);
        Player1Task plater1 = new Player1Task(player1.getTargetLocations(), true);
        Player2Task plater2 = new Player2Task(player2.getTargetLocations(), false);

        Thread t1 = new Thread(plater1);
        Thread t2 = new Thread(plater2);

        t1.start();
        t2.start();
    }

    @Override
    public void over() {

    }


    class Player1Task implements Runnable {
        private List<TargetLocation> playerOnesTargetLocationList;
        private boolean isHitTarget = false;
        private int fireCount = 0;
        private boolean yourTern;

        Player1Task(List<TargetLocation> playerOnesTargetLocationList, boolean yourTern) {
            this.playerOnesTargetLocationList = playerOnesTargetLocationList;
            this.yourTern = yourTern;
        }

        @Override
        public void run() {
            try {
                lock.lock();
                fire();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        private void fire() throws InterruptedException {
            while (fireCount != playerOnesTargetLocationList.size()) {
                if (!yourTern) {
                    notPlayer1TernCondition.await();
                }
                TargetLocation location = playerOnesTargetLocationList.get(fireCount);
                if (player2.getOwnField().hasShip(location.getxPos(), location.getyPos())) {

                } else {
                    System.out.println("Player-1 else");
                    yourTern = false;
                    notPlayer2TernCondition.signalAll();
                }
                fireCount++;
            }

        }

    }

    class Player2Task implements Runnable {
        private List<TargetLocation> playerTwosTargetLocationList;
        private boolean isHitTarget = false;
        private int fireCount = 0;
        private boolean yourTern;

        Player2Task(List<TargetLocation> playerTwosTargetLocationList, boolean youTern) {
            this.playerTwosTargetLocationList = playerTwosTargetLocationList;
            this.yourTern = youTern;
        }

        @Override
        public void run() {
            lock.lock();
            try {
                fire();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }

        private void fire() throws InterruptedException {

            while (fireCount != playerTwosTargetLocationList.size()) {
                if (!yourTern) {
                    notPlayer2TernCondition.await();
                }

                TargetLocation location = playerTwosTargetLocationList.get(fireCount);
                if (player1.getOwnField().hasShip(location.getxPos(), location.getyPos())) {

                } else {
                    System.out.println("p2 else");
                    yourTern = false;
                    notPlayer1TernCondition.signalAll();
                }
                fireCount++;
            }

        }
    }
}

Above code is not working as per expectation, First time Player-1 executes and after that code stuck.

Any explanation is quite appreciated.


Solution

  • You are never setting yourTern back to true. (A shared variable signifying the which player has the turn can be used instead)

    Explanation: Assume initially Player1 has the lock and fires as Player1's yourTern is true. Assume it misses then you would signal Player2(which is not yet awaiting) and set yourTern to false and releases the lock(by calling notPlayer1TernCondition.await() method in next iteration).
    This lock will be aquired by Player2 and it would call notPlayer2TernCondition.await() as its yourTern is false.
    Both thread would now go to awaiting state forever.