gpt4 book ai didi

java - 为什么我的等待线程即使收到通知也没有醒来?

转载 作者:行者123 更新时间:2023-11-29 04:49:57 26 4
gpt4 key购买 nike

我有一个客户端服务器井字游戏,它试图为每个玩家运行不同的线程(在不同的终端中),这是我在 eclipse 中构建的。

我的目标是让每个玩家移动,.notify() 另一个玩家,然后 .wait() 等待另一个玩家移动,并交替执行该过程,直到游戏结束。

toSync是用于同步的对象

public static final Object toSync = new Object()

它位于 Player 类中(由 XPlayer 和 OPlayer 扩展)。

在 XPlayer 和 Oplayer 中注释了似乎导致问题的行:

Xplayer和OPlayer都有main方法,可以并发运行。 X 进行第一步操作,然后使用套接字将此操作传递给服务器。
服务器将此着法传递给 O,然后 O 做出自己的着法并将其传回给服务器。这种情况交替进行,直到游戏结束。

作为 x 玩家迈出第一步工作正常,但一旦做出初始移动,o 应该显示棋盘,然后提示用户他们的移动。然而,这并没有发生:x 开始行动,并且 o 理应收到通知,但实际上从未醒来。永远不会到达 OPlayer 中注释的结束 while 循环的大括号(根据我到目前为止所做的调试,我知道这是真的)。​​

XPlayer 类:

import java.io.*;

public class XPlayer
extends Player
implements Runnable
{
public static volatile boolean xTurn = true;

public XPlayer() throws IOException
{
super();
mark = LETTER_X;
}

public void run()
{
try
{
System.out.println("Okay " + name + ", You will be the X-Player");

synchronized(toSync)
{
Cell move = makeMove();
out.println(move.toString());
board.addMark
(move.row(),move.col(),move.mark());
board.display();

xTurn = false;
toSync.notifyAll(); //THIS IS THE LINE THAT ISNT WORKING!!

System.out.println(WAITING);
}
synchronized(toSync)
{
while (!xTurn)
{toSync.wait();}
}

while (!board.isOver())
{
synchronized(toSync)
{
String line;
do {line = in.readLine();}
while (line == null);

Cell opponentMove = Cell.split(line);
board.addMark
(opponentMove.row(),opponentMove.col(), opponentMove.mark());

String move = makeMove().toString();
out.println(move);
xTurn = false;
toSync.notifyAll();

while (!xTurn)
{toSync.wait();}
}
}

endGame();

sock.close();
in.close();
stdin.close();
out.close();

} catch (InterruptedException ie)
{
System.out.println("IE IN XPLAYER! " + ie.getMessage());
System.exit(1);

} catch (IOException ioe)
{
System.out.println("IOE IN XPLAYER! " + ioe.getMessage());
System.exit(1);
}
}
public static void main(String[] args)
{
try
{
XPlayer x = new XPlayer();
Thread t = new Thread(x);
t.start();

} catch(IOException ioe)
{
System.err.println
("IOE IN XPLAYER MAIN " + ioe.getMessage());
System.exit(1);
}
}

OPlayer 类:

import java.io.*;

public class OPlayer
extends Player
implements Runnable
{

public OPlayer() throws IOException
{
super();
mark = LETTER_O;
}

public void run()
{
try
{
synchronized(toSync)
{
System.out.println("Okay " + name + ", You will be the O-Player");

System.out.println(WAITING);
while(!XPlayer.xTurn)
{toSync.wait();} // THIS IS THE LINE THAT ISN'T WAKING UP

while (!board.isOver())
{
String line;

do {line = in.readLine();}
while (line == null);

Cell opponentMove = Cell.split(line);
board.addMark
(opponentMove.row(),opponentMove.col(),opponentMove.mark());

Cell move = makeMove();
out.println(move.toString());
board.addMark(move.row(),move.col(),move.mark());
board.display();
XPlayer.xTurn = true;
toSync.notifyAll();

System.out.println(WAITING);
while (XPlayer.xTurn)
{toSync.wait();}
}
}

endGame();

sock.close();
in.close();
stdin.close();
out.close();

} catch (InterruptedException ie)
{
System.out.println("IE IN OPLAYER " + ie.getMessage());
System.exit(1);

} catch (IOException ioe)
{
System.err.println("IOE IN OPLAYER " + ioe.getMessage());
System.exit(1);
}
}

public static void main(String[] args)
{
try
{
OPlayer o = new OPlayer();
Thread t = new Thread(o);
t.start();

} catch(IOException ioe)
{
System.err.println("IOE IN OPLAYER MAIN" + ioe.getMessage());
System.exit(1);
}
}
}

如代码所示,XPlayer 中的 toSync.notifyAll() 调用没有唤醒 OPlayer 线程,一旦 XPlayer 采取了第一步,我就陷入了僵局

我相信只需要这两个类来解决这个问题,但为了以防万一,这里有 Player Board 和 TTTServer 类:类玩家:

import java.net.*;
import java.io.*;

public class Player
implements Constants
{
protected static final Object toSync = new Object();

protected Socket sock;
protected BufferedReader stdin;
protected BufferedReader in;
protected PrintWriter out;

protected String name;
protected char mark;
protected Board board;

public Player() throws IOException
{
sock = new Socket("localhost",1298);
stdin = new BufferedReader(new InputStreamReader(System.in));
in = new BufferedReader(new
InputStreamReader(sock.getInputStream()));
out = new PrintWriter(sock.getOutputStream(),true);

System.out.println(WELCOME);
System.out.println("Please Enter your name:");
name = stdin.readLine();
board = new Board();
}

public Cell makeMove() throws IOException
{
board.display();

int row = -1;
int col = -1;
do
{
while (row < 0 || row > 2)
{
System.out.println
(name + ", what row would you like your next move to be in?");
row = Integer.parseInt(stdin.readLine());
if (row < 0 || row > 2)
{System.out.println("Invalid entry! Try again...");}
}
while (col < 0 || col > 2)
{
System.out.println
(name + ", what column would you like your next move to be in?");
col = Integer.parseInt(stdin.readLine());
if (col < 0 || col > 2)
{System.out.println("Invalid entry! Try again...");}
}

if (board.getMark(row, col) != SPACE_CHAR)
{System.out.println("That spot is already taken Try again...");}

} while (board.getMark(row,col) != SPACE_CHAR);

return new Cell(row,col,mark);
}

public void endGame()
{
if (board.xWins() == 1) {System.out.println(END + XWIN);}
if (board.oWins() == 1) {System.out.println(END + OWIN);}
else {System.out.println(END + " It was a tie!!");}
}
}

类 TTTServer:

import java.net.*;
import java.io.*;

public class TTTServer
implements Constants
{
public static void main(String[] args)
{
try
{
ServerSocket ss = new ServerSocket(1298,2);
System.out.println("The Server is running...");
Socket sock;

Board board = new Board();

sock = ss.accept();
sock = ss.accept();

BufferedReader in = new BufferedReader(new
InputStreamReader(sock.getInputStream()));
PrintWriter out = new PrintWriter(sock.getOutputStream(),true);

do
{
String moveString;

do {moveString = in.readLine();}
while (moveString == null);

Cell move = Cell.split(moveString);
board.addMark(move.row(), move.col(), move.mark());

out.println(moveString);

} while(!board.isOver());

in.close();
out.close();
ss.close();
sock.close();

} catch(IOException ioe)
{
System.out.println("IOE IN TTTSERVER " + ioe.getMessage());
System.exit(1);
}

}
}

类(class)委员会:

public class Board 
implements Constants
{
/**
* A 2D char array stores the game board and
* the total number of marks
*/
private char theBoard[][];
private int markCount;
/**
* Default constructor initializes the array and fills it with
* SPACE_CHARs from the Constants interface
*/
public Board()
{
markCount = 0;
theBoard = new char[3][];
for (int i = 0; i < 3; i++) {
theBoard[i] = new char[3];
for (int j = 0; j < 3; j++)
theBoard[i][j] = SPACE_CHAR;
}
}
/**
* Getter for the mark at the location specified by the arguments
*
* @param row
* @param column
*
* @return mark
*/
public char getMark(int row, int col)
{return theBoard[row][col];}
/**
* Getter for the number of moves which have been made thus far
*
* @return markCount
*/
public int getMarkCount() {return markCount;}
/**
* @return true if the game is over, otherwise false
*/
public boolean isOver()
{
if (xWins() == 1 || oWins() == 1 || isFull())
{return true;}

return false;
}
/**
* @return true if the board has been completely filled with
* X_CHARs and O_CHARs from Constants interface, else false
*/
public boolean isFull()
{return markCount == 9;}
/**
* Runs checkWinner on LETTER_X from Constants interface
*
* @return true if X has won, else false
*/
public int xWins()
{return checkWinner(LETTER_X);}
/**
* Runs checkWinner on LETTER_O from Constants interface
*
* @return true if O has won, else false
*/
public int oWins()
{return checkWinner(LETTER_O);}
/**
* Uses the formatting helper methods to display the board
* in the console
*/
public void display()
{
displayColumnHeaders();
addHyphens();
for (int row = 0; row < 3; row++) {
addSpaces();
System.out.print(" row " + row + ' ');
for (int col = 0; col < 3; col++)
System.out.print("| " + getMark(row, col) + " ");
System.out.println("|");
addSpaces();
addHyphens();
}
}
/**
* Add the mark in the last argument to the location specified by the
* first two arguments
*
* @param row
* @param column
* @param mark
*/
public void addMark(int row, int col, char mark)
{
theBoard[row][col] = mark;
markCount++;
}
/**
* Clears the board by replacing all marks with
* SPACE_CHARs from the Constants interface
*/
public void clear()
{
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
theBoard[i][j] = SPACE_CHAR;
markCount = 0;
}
/**
* Checks if the player with the argument mark has won the game
*
* @param mark
*
* @return true if the game was won, else false
*/
int checkWinner(char mark) {
int row, col;
int result = 0;

for (row = 0; result == 0 && row < 3; row++) {
int row_result = 1;
for (col = 0; row_result == 1 && col < 3; col++)
if (theBoard[row][col] != mark)
row_result = 0;
if (row_result != 0)
result = 1;
}


for (col = 0; result == 0 && col < 3; col++) {
int col_result = 1;
for (row = 0; col_result != 0 && row < 3; row++)
if (theBoard[row][col] != mark)
col_result = 0;
if (col_result != 0)
result = 1;
}

if (result == 0) {
int diag1Result = 1;
for (row = 0; diag1Result != 0 && row < 3; row++)
if (theBoard[row][row] != mark)
diag1Result = 0;
if (diag1Result != 0)
result = 1;
}
if (result == 0) {
int diag2Result = 1;
for (row = 0; diag2Result != 0 && row < 3; row++)
if (theBoard[row][3 - 1 - row] != mark)
diag2Result = 0;
if (diag2Result != 0)
result = 1;
}
return result;
}

/**
* The final three helper methods are called by display
* to format the board properly in the console
*/
void displayColumnHeaders() {
System.out.print(" ");
for (int j = 0; j < 3; j++)
System.out.print("|col " + j);
System.out.println();
}

void addHyphens() {
System.out.print(" ");
for (int j = 0; j < 3; j++)
System.out.print("+-----");
System.out.println("+");
}

void addSpaces() {
System.out.print(" ");
for (int j = 0; j < 3; j++)
System.out.print("| ");
System.out.println("|");
}
}

最佳答案

这是你的错误:

Both Xplayer and OPlayer have main methods, so that they can be run concurrently.

如果您正在运行两个 main() 方法,它们不会“同时”运行;它们是完全独立的过程。这意味着没有共享线程、变量、对象、通知等。如果你想共享状态,你需要从一个 main() 方法开始一切:

class StarterClass {
public static void main(String[] args)
{
// start XPlayer thread
try
{
XPlayer x = new XPlayer();
Thread t = new Thread(x);
t.start();

} catch(IOException ioe)
{
System.err.println
("IOE IN XPLAYER MAIN " + ioe.getMessage());
System.exit(1);
}

// start OPlayer thread
try
{
OPlayer o = new OPlayer();
Thread t = new Thread(o);
t.start();

} catch(IOException ioe)
{
System.err.println("IOE IN OPLAYER MAIN" + ioe.getMessage());
System.exit(1);
}
}
}

如果您的意图是让每个 Player 在轮流交替时作为单独的客户端运行,则线程同步是不适合这项工作的工具。您需要在服务器和客户端之间实现自定义消息传递,以保持它们同步。

关于java - 为什么我的等待线程即使收到通知也没有醒来?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35835416/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com