Почему связь с потоками не работает в Java?

#java #multithreading #java.util.concurrent

#java #многопоточность #java.util.concurrent

Вопрос:

Я работаю над небольшой игрой на основе Java, я пытаюсь запустить ракету игроком-1, пока игрок-1 не промахнется мимо цели, как только игрок-1 промахнется мимо цели, тогда огненная крачка перейдет к игроку-2, игрок-2 начнет стрелять, пока не промахнется мимо своей цели, наоборот.

Здесь Player-1 и Player-2 оба являются задачами Java Runnable , пожалуйста, найдите приведенный ниже код :

 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  ;
            }

        }
    }
}
  

Приведенный выше код работает не так, как ожидалось, при первом запуске Player-1 и после этого код застрял.

Приветствуется любое объяснение.

Ответ №1:

Вы никогда не устанавливаете значение yourTern обратно в true. (Вместо этого можно использовать общую переменную, указывающую, у какого игрока ход)

Объяснение: Предположим, что изначально Player1 имеет блокировку и срабатывает, поскольку ваш запрос Player1 имеет значение true. Предположим, что она пропускает, тогда вы бы подали сигнал Player2 (который еще не ожидает) и установили yourTern в false и сняли блокировку (вызвав notPlayer1TernCondition.await() метод на следующей итерации).
Эта блокировка будет получена Player2, и она будет вызываться notPlayer2TernCondition.await() , поскольку ее значение yourTern равно false.
Теперь оба потока навсегда перейдут в состояние ожидания.