Java 线程等待用户单击某个内容

Java 线程等待用户单击某个内容,java,multithreading,swing,exception,mouselistener,Java,Multithreading,Swing,Exception,Mouselistener,我正在准备玩五子棋的申请 我已经创建了漂亮的GUI,现在我正在与核心引擎进行斗争 有一个类GameEngine,它有同步的方法来移动。 还有一些类实现了IClient接口,它们是“玩家”。 首先要做的是实现PlayerClient,它连接到BoardPanel,并在BoardPanel(代表gomoku板)中的MouseListener打开时移动。我希望我的应用程序是开放的,以实现也电脑播放器。这就是为什么它如此复杂 所以。。。问题: 我的GameEngine类如下所示: public clas

我正在准备玩五子棋的申请

我已经创建了漂亮的GUI,现在我正在与核心引擎进行斗争

有一个类
GameEngine
,它有同步的方法来移动。 还有一些类实现了
IClient
接口,它们是“玩家”。 首先要做的是实现
PlayerClient
,它连接到
BoardPanel
,并在
BoardPanel
(代表gomoku板)中的
MouseListener
打开时移动。我希望我的应用程序是开放的,以实现也电脑播放器。这就是为什么它如此复杂

所以。。。问题: 我的
GameEngine
类如下所示:

public class GameEngine {
    private IClient blackPlayer;
    private IClient whitePlayer;
    private GameState gameState;

    ...

    public void play() {
        blackPlayer.run();
        whitePlayer.run();
    }

    public synchronized void move(Move move) throws IllegalMoveException {
        gameState.move(move);
        if (move.isBlackMove()){
            whitePlayer.notify();
        }else{
            blackPlayer.notify();
        }
    }

    public synchronized void waitForYourTurn(boolean color){
        try {
            while (gameState.isBlackToMove()!=color) {
                wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
private synchronized void movePicked() {
    if (gameState.isBlackToMove() && blackClient != null) {
        blackClient.notify();
        clearCurrentMove();
    }
    if (!gameState.isBlackToMove() && whiteClient != null) {
        whiteClient.notify();
        clearCurrentMove();
    }
}
我的客户端类有run()方法:

在我写“//waitForPickedMove()”的地方,客户端应该等待用户单击主板上的正确位置。所以我的董事会班上有一个鼠标听器:

private class MoveMouseListener implements MouseListener {
        @Override
        public synchronized void mouseReleased(MouseEvent e) {
            if (gameState == null) {
                return;
            }

            if (currentMove != null) {
                movePicked();
                repaint();
            }
        }
    }
currentMove当然是用户通过点击线路板选择的移动。movePicked()的外观如下所示:

public class GameEngine {
    private IClient blackPlayer;
    private IClient whitePlayer;
    private GameState gameState;

    ...

    public void play() {
        blackPlayer.run();
        whitePlayer.run();
    }

    public synchronized void move(Move move) throws IllegalMoveException {
        gameState.move(move);
        if (move.isBlackMove()){
            whitePlayer.notify();
        }else{
            blackPlayer.notify();
        }
    }

    public synchronized void waitForYourTurn(boolean color){
        try {
            while (gameState.isBlackToMove()!=color) {
                wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
private synchronized void movePicked() {
    if (gameState.isBlackToMove() && blackClient != null) {
        blackClient.notify();
        clearCurrentMove();
    }
    if (!gameState.isBlackToMove() && whiteClient != null) {
        whiteClient.notify();
        clearCurrentMove();
    }
}
我尝试在许多地方放置
wait()
。我尝试反向控制并将其放入
Board
类中,因此它调用了客户机类中的方法(setCurrentMove(Move-Move))。不幸的是,我无法达到我想要的。我总是得到
IllegalMonitorStateException
或我的GUI块

我希望我能充分解释我的问题。我会感谢你的帮助

编辑:

我很确定我应该同步某个东西,但我真的不知道是什么

编辑2:

@Override
    public void enemyMoved() {
        myTurn = true;
        executorService.move();
    }

    private class ExecutorService implements Runnable {

        @Override
        public void run() {
            while (gameState.getWinner() == 0) {
                System.out.println("Calculating: j= " + j);
                if (j == 3)
                    j = 4;
                else
                    j = 3;

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }

        public void move() {
            while (myTurn) {
                try {
                    gameEngine.move(new Move(black, j, i++));
                    myTurn = false;
                } catch (IllegalMoveException e) {
                    e.printStackTrace();
                }
            }
        }

    }

很难说它到底是什么:很多碎片。但看起来您应该按照以下说明同步通知呼叫:


()

很难说清楚它到底是什么:很多碎片。但看起来您应该按照以下说明同步通知呼叫:


()

嗨,我建议你睡觉()并通知()。如果您想在未知时间停止某个线程,请让它睡眠,当您再次需要它时,请让它通知()。

嗨,我建议您睡眠()和通知()。如果您想在未知时间停止某个线程,请让它睡眠,当您再次需要它时,请让它通知()。

游戏引擎无需一直占用线程,在无事可做时将其阻塞。您应该将其重新设计为反应式:代码在事件处理程序正在执行的线程中有事件时执行。这样您就不需要任何
等待
-
通知
机制


如果您希望允许播放器实现在不占用调用线程的情况下从容进行,请在设计API时牢记异步性:
IClient
将有一个表示“其他播放器已移动”的方法,该方法不会立即返回播放器的移动。
IClient
将在移动时调用游戏引擎上的一个方法。

游戏引擎不需要不断占用线程,在无事可做时阻塞线程。您应该将其重新设计为反应式:代码在事件处理程序正在执行的线程中有事件时执行。这样您就不需要任何
等待
-
通知
机制


如果您希望允许播放器实现在不占用调用线程的情况下从容进行,请在设计API时牢记异步性:
IClient
将有一个表示“其他播放器已移动”的方法,该方法不会立即返回播放器的移动。
IClient
将通过其移动调用游戏引擎上的一个方法。

“这就是为什么它如此复杂的原因。”为了更快地获得更好的帮助,只需多线程和鼠标单击即可发布您的最佳尝试。Swing。嗯,这是一个很大的应用程序,现在有很多类。我试图删掉重要的东西。游戏引擎和客户端之间的多线程工作正常。我试着硬编码这个动作。当我尝试等待GUI时出现问题。我只是不确定应该等待什么以及应该在哪里得到通知。所以基本上我需要帮助来实现这个注释:Move waitForPickedMove()和通知somhow。。。与movePicked()中的不完全一样。“这就是为什么它如此复杂。”为了更快地获得更好的帮助,请发布一篇您的最佳尝试,只需使用多线程和鼠标单击。Swing。嗯,这是一个很大的应用程序,现在有很多类。我试图删掉重要的东西。游戏引擎和客户端之间的多线程工作正常。我试着硬编码这个动作。当我尝试等待GUI时出现问题。我只是不确定应该等待什么以及应该在哪里得到通知。所以基本上我需要帮助来实现这个注释:Move waitForPickedMove()和通知somhow。。。与movePicked()中的不完全一样,您能给我展示一下您的方法的简单示例吗?我想我不明白。多线程是很难的,除非你能很好地理解它。:)我的意思是,例如,一个简单的应用程序,其中两个线程互相等待,每个线程都等待单击鼠标,例如,将光标坐标写入控制台。您的设计先验地将一个播放器耦合到一个线程,这就是问题所在。在IClient中放置一个方法,当对方玩家移动时调用该方法;这可以是一个
void
方法(一个经典回调)。游戏引擎还拥有一个回调方法,可以接收玩家的移动。人类玩家不需要自己的线程——它响应GUI上的操作。计算机播放器也不是线程:它可以在内部使用线程进行处理。当调用其“对方玩家移动”方法时,它向ExecutorService提交任务,ExecutorService计算。。。。。。移动并调用相应的游戏方法。感谢福克斯的解释,现在我将尝试实现你告诉我的。我会在这里写我的日志。好的,我已经完成了,它对PlayerClient有效。不幸的是,我在使用Runnable类(执行器服务)时仍然存在问题。我仍然收到这个非法的监视器