2016-08-20 89 views
1

在下面的代碼中,我使用wait()-notify()實現了線程間通信,它給了我期望的輸出。 預計輸出:123456789實際輸出:123456789線程信號序列

我的問題是,是否有任何保證總是'主線程'將獲得第一次執行機會,因爲線程調度依賴於jvm。如果'子線程'獲得第一次機會,則notify()信號將會丟失,並且'主線程'將永遠等待。我如何確認'主線程'將始終執行。另請確認下面的代碼是否可以改進。

package com.test.Thread; 

public class ThreadExample1 { 

    public static void main(String[] args) throws InterruptedException{ 

     ThreadChild1 lockingObj = new ThreadChild1(); 
     lockingObj .start(); 
     synchronized(lockingObj){ 
      for(int i=1;i<10;i++){ 
       System.out.println("Main "+i); 
      } 
      lockingObj.wait(); 
      System.out.println("Main got notified"); 

     } 

    } 

} 

class ThreadChild1 extends Thread{ 

    public void run(){ 
     synchronized(this){ 
      for(int i=1;i<10;i++){ 
       System.out.println("Child "+i); 
      } 
      this.notify(); 
      } 
    } 
} 

回答

3

你的代碼是錯誤的,你提到你自己的原因:你不能確定哪個線程先行。 還有其他的東西可能會出錯 - wait可以在沒有notify的情況下喚醒。

您可以在Javadoc for the wait method,這也解釋了你應該做的閱讀它:

正如一個參數的版本,中斷和虛假喚醒是 可能的,而且這種方法應該總是在使用一個循環:

synchronized (obj) { 
    while (<condition does not hold>) 
     obj.wait(); 
    ... // Perform action appropriate to condition 
} 

在你的代碼,你可以用表達條件的布爾變量解決這個問題:「我被告知」:

public class ThreadExample1 { 

    public static void main(String[] args) throws InterruptedException { 
     ThreadChild1 lockingObj = new ThreadChild1(); 
     lockingObj.start(); 

     synchronized (lockingObj) { 
      for(int i = 1; i < 10; i++) { 
       System.out.println("Main " + i); 
      } 
      while (!lockingObj.haveNotified) { 
       lockingObj.wait(); 
      } 
      System.out.println("Main got notified"); 
     } 

    } 

} 

class ThreadChild1 extends Thread{ 
    private boolean haveNotified; 
    public void run(){ 
     synchronized (this) { 
      for (int i = 1; i < 10; i++) { 
       System.out.println("Child " + i); 
      } 
      haveNotified = true; 
      this.notify(); 
     } 
    } 
} 
+0

謝謝@Erwin。理解並糾正它。 – RoyalTiger

1

雖然這可以在您的系統上正常工作,但這不是保證,因爲您懷疑可能會在不同的系統上變爲真實。線程行爲很難/不可能預測。因此,我喜歡在最糟糕的情況下進行思考,如果我能想出可能出現的突發情況(正如您剛纔所描述的那樣),我只需重新設計以確保其可行。

測試代碼的一個很好的技巧就是在關鍵時刻暫停/暫停線程,方法是在IDE中添加一個斷點,如果可能(非失敗保護)添加一個非常耗時的任務/調用,或者通過停頓線程(並不總是理想的)。除了我確定在這種類型的測試中還有一些庫可以擴展。

我希望這可以幫助你在正確的方向上有點。

+0

謝謝n247s ..我想根據你的建議來測試。我明白了。線程行爲確實很難預測,這就是爲什麼我很困惑。 – RoyalTiger