2015-10-17 57 views
0

我正在编写一个GUI游戏,我想等待游戏结束,然后再返回赢家。然而,由于我的游戏经理类与用于实现游戏逻辑和发现胜利的课程是分开的,因此我想知道如何让游戏经理等待,直到其他课程通知其获胜为止,然后继续执行其他的东西。我之前并没有真正使用过多线程,所以我希望有人能够解释我如何实现这一目标。
下面是从游戏管理类的主要一些相关的代码,我已经试过:如何在继续当前线程之前等待事件发生?

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

从游戏类:

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

+1

我建议以 '甲骨文并发教程'。 –

回答

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

0

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

如果你确实希望你的GUI和游戏逻辑运行在不同的线程上,似乎你正试图实现描述为here的锁定方法。有几件事情需要注意的:

  • 的JVM可以给你一个等待线程的InterruptedException在任何时间,以任何理由。在继续之前,您应该始终检查导致您等待的情况。
  • 无论您何时访问跨线程共享的状态,都需要确保正确使用​​和volatile
  • 如果您锁定WINNER,请记住此字段可以更改。如果BoardWINNER上锁定并更改其值,则在Board块完成之前,进入Game的新线程可以自由获取其锁定,因为它们锁定了不同的对象。
+0

我的线程方法与您提供的链接描述的方法不同吗?它在我看来,他们是相同的格式?然而,出于某种原因,当我尝试这样做时,gui会以空白屏幕冻结 –

+0

看起来您正在使用相同的方法,但如果没有'BoardFrame'的代码,就很难说更多。这听起来像你需要使用调试器来找出程序卡住的地方。程序问题也是如此 - 如果您有特定问题,请将其包含在您的问题中,GUI冻结与通知模式完全不同。 – hugh

+0

我修复了GUI问题,但我仍然遇到线程问题。请看我的编辑 –

相关问题