如何在继续当前线程之前等待事件发生?

时间:2015-10-17 09:11:00

标签: java multithreading

我正在编写一个GUI游戏,我想等到游戏结束,然后才能回归获胜者。但是,由于我的游戏管理器类与用于实现游戏逻辑并检测到胜利的类是分开的,我想知道如何让游戏管理器等到另一个类通知它获胜,然后继续做其他的东西。我以前在多线程方面并没有太多工作,所以我希望有人可以解释我是如何实现这一点的。
以下是来自GameManager类的一些相关代码'我试过的主要内容:

...
Game game = new Game(mode);
String winner = game.getWinner();
...

从Game类:

public Game(Game.Mode mode){
    this.board = new Board(7);
    window = new BoardFrame(7, 7, mode, board); //Graphical interface
    window.setVisible(true);
}

public String getWinner(){
    synchronized(board.WINNER){
        try {
            board.WINNER.wait();
        } catch (InterruptedException e) {}
    }
    return board.WINNER;
}

董事会成员:

public boolean update(int num){

    if (isValidMove(CurrentPlayer, num)){
        buttonClients.get(positions.get(CurrentPlayer)).clear();

        positions.put(CurrentPlayer, num);
        board[num] = 1;
        buttonClients.get(num).performCallback(CurrentPlayer);

        if ((WINNER = isGameFinished())!=""){
            //Disable all further inputs
            for (int i = 0; i<board.length; i++){
                board[i] = 1;
            }
            synchronized (WINNER) {
                WINNER.notify();
            }                                   
        }

        CurrentPlayer = (CurrentPlayer==PLAYER1)?PLAYER2:PLAYER1;
        return true;        
    }
    return false;
}

编辑:所以我找到了屏幕显示问题的原因,即GameManager的所有代码都在EventQueue.invokeLater()块中。我现在已经把它从那个块中拿出来了,现在屏幕显示正常。但是,当我玩到最后,synchronized(WINNER)块最终运行时,似乎没有任何反应?换句话说,游戏继续等待WINNER

2 个答案:

答案 0 :(得分:1)

当我在线程上等待时,我最喜欢的是使用CountDownLatch并使用Callable<V>并将其提交给线程执行器,该线程执行器返回Future<V>块直到线程完成。

public class Example {
    ExecutorService executorService = Executors.newCachedThreadPool();
    public void init(){
        CountDownLatch latch = new CountDownLatch(1);
        Future<Boolean> submit = executorService.submit(new Thread3());
        executorService.execute(new Thread1(latch, submit));
        executorService.execute(new Thread2(latch));
    }

    public class Thread1 implements Runnable{
        private CountDownLatch latch;
        private Future<Boolean> thread3;
        public Thread1(CountDownLatch latch, Future<Boolean> thread3) {
            this.latch = latch;
            this.thread3 = thread3;
        }

        @Override
        public void run() {
            int i = 0;
            try {
                thread3.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            while (i < 50){
                LockSupport.parkNanos(1000);
                i++;
            }
            latch.countDown();
        }
    }

    public class Thread2 implements Runnable{
        private CountDownLatch latch;

        public Thread2(CountDownLatch latch) {
            this.latch = latch;
        }

        @Override
        public void run() {
            try {
                latch.await();
                System.out.println("We can continue");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    public class Thread3 implements Callable<Boolean>{

        @Override
        public Boolean call() throws Exception {
            int i = 0;
            while (i < 50){
                LockSupport.parkNanos(1000);
                i++;
            }
            return true;
        }
    }

}

良好的资源: http://tutorials.jenkov.com/java-concurrency/index.html

答案 1 :(得分:0)

有几种方法可以做到这一点,但到目前为止,最好的方法是使用observer pattern来创建事件监听器。这种模式背后的想法是允许代码在事件发生时注册要执行的操作,同时将事件处理程序与它要调用的操作隔离开来。请注意,此解决方案不需要任何多线程。

如果您确实希望您的GUI和游戏逻辑在不同的线程上运行,那么您似乎正在尝试实现here所述的锁定方法。需要注意以下几点:

  • 由于任何原因,JVM可以随时为您提供InterruptedException等待线程。在继续操作之前,您应该始终检查导致您等待的条件。
  • 每当您访问跨线程共享的状态时,您需要确保正确使用synchronizedvolatile
  • 您锁定WINNER的位置,请记住此字段可能会发生变化。如果在Board上锁定了WINNER并更改了其值,则在Game块完成之前,输入Board的新主题可以自由获取其锁定,因为他们可以使用temp=line[IndexEnd:IndexStart]; 重新锁定不同的物体。