#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.
Теперь оба потока навсегда перейдут в состояние ожидания.