2015-10-17 88 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問題,但我仍然遇到線程問題。請看我的編輯 –

相關問題