线程等待用户点击某事

时间:2012-12-07 08:27:43

标签: java multithreading swing exception mouselistener

我正准备申请玩gomoku。

我创建了漂亮的GUI,现在我正在与核心引擎作斗争。

有一个类GameEngine,它具有同步方法来进行移动。 还有一些实现IClient接口的类是“玩家”。 首先要做的是实现与PlayerClient相关联的BoardPanel,并在MouseListener(代表gomoku board)sais中BoardPanel时移动。我希望我的应用程序可以实现计算机播放器。这就是它如此复杂的原因。

所以......问题: 我的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();
        }
    }

}

我的Client类有run()方法:

@Override
    public void run() {
        while (gameState.getWinner() == 0) {
            move = null;
            boolean moved = false;
            while (!moved) {
                gameEngine.waitForYourTurn(black);
                try {
                    //waitForPickedMove();
                    gameEngine.move(move);
                    moved = true;
                } catch (IllegalMoveException e) {
                    e.printStackTrace();
                }
            }
        }
    }

在那里,我写了“// waitForPickedMove()”客户端应该等待用户点击板上的正确位置。所以...我的Board类中有一个MouseListener:

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

            if (currentMove != null) {
                movePicked();
                repaint();
            }
        }
    }

currentMove当然是由用户通过点击棋盘来选择。虽然movePicked()看起来像这样:

private synchronized void movePicked() {
    if (gameState.isBlackToMove() && blackClient != null) {
        blackClient.notify();
        clearCurrentMove();
    }
    if (!gameState.isBlackToMove() && whiteClient != null) {
        whiteClient.notify();
        clearCurrentMove();
    }
}

我试图将wait()放在很多地方。我试图反向控制并将其放入Board类,因此它调用了Client类中的方法(setCurrentMove(Move move))。不幸的是,我无法达到我想要的。我总是得到IllegalMonitorStateException或我的GUI块。

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

编辑:

public class MockComputerClient implements IClient {
    private GameState gameState;
    private GameEngine gameEngine;
    private boolean black;
    private ExecutorService executorService;
    private boolean myTurn = false;
    private int i = 3;

    public MockComputerClient(GameEngine gameEngine, GameState gameState,
            boolean black) {
        this.gameEngine = gameEngine;
        this.gameState = gameState;
        this.black = black;
        executorService = new ExecutorService();
        executorService.run();
    }

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

    private class ExecutorService implements Runnable {

        @Override
        public void run() {
            while (gameState.getWinner() == 0) {
                try {
                    while (!myTurn) {
                        wait();
                    }
                    // Hardcoded Moves
                    gameEngine.move(new Move(black, 3, i++));
                    myTurn = false;
                } catch (InterruptedException | IllegalMoveException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

我很确定我应该同步,但我真的不知道是什么。

编辑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();
                }
            }
        }

    }

3 个答案:

答案 0 :(得分:4)

游戏引擎不需要经常占用一个线程,当没有任何事情可以阻止它时。你应该重新设计它是被动的:代码在有事件时执行,在执行事件处理程序的线程中。那么您将不需要任何wait - notify机制。

如果你想让Player实现在不占用调用线程的情况下花费时间,请考虑异步性设计API:IClient将有一个表示“其他玩家已移动”的方法,该方法不会返回球员立即行动。预计IClient将在游戏引擎上调用一个方法。

答案 1 :(得分:0)

很难确切地知道它是什么:很多碎片。但看起来你应该同步你的通知电话,如下所述:

http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#notify()

答案 2 :(得分:0)

嗨我建议你睡觉()并通知()。如果你想在未知的时间停止一些线程让它睡觉,当你需要它时再给它notify()。