2014-11-08 67 views
3

我不熟悉Java併發。我有一個簡單的對象與3個方法,每個對應的代碼運行3個不同的線程。爲什麼notifyAll()語句在這種情況下不會釋放其他兩個線程中的等待?爲什麼notifyAll()在這種簡單情況下不能恢復其他線程?

public class Main { 
static class Obj { 
     synchronized void t1() { 
      System.out.println("T1 ran"); 
      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      notifyAll(); 
     } 
    synchronized void t2() { 
     try { 
      wait(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("T2 ran"); 
    } 
    synchronized void t3() { 
     try { 
      wait(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("T3 ran"); 
    } 
} 

public static void main(String[] args) { 
    final Obj o = new Obj(); 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      o.t1(); 
     } 
    }).start(); 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      o.t2(); 
     } 
    }).start(); 
    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      o.t3(); 
     } 
    }).start(); 
}} 

我預計: T1跑 ~~停頓1秒~~ T2跑 T3跑

我: T1跑

回答

6

Thread.sleep不釋放或在wait的方式做放鬆任何鎖,所以同步仍處於完整的效果和其他線程將不會被允許在睡眠期間進入他們的方法。

如果更換

Thread.sleep(1000); 

wait(1000); 

其他線程將被允許拍攝相同的鎖定,輸入方法,開始等待,併爲您預期的樣品將工作。

+0

真棒謝謝! – 2014-11-08 21:29:31

+0

@其他人:我只用包含方法't1,t2,t3'(Obj1,Obj2,Obj3)的3個不同的「對象」測試源代碼 - 結果是相同的。爲什麼在Obj1上的同步方法會阻止不同的線程分別訪問'Obj2.t2'和'Obj3.t3'? – dognose 2014-11-08 21:39:58

+0

啊沒關係 - 其他方法已經被發現,但是。 'notifyAll'沒有影響,然後:-)所以其他對象線程正在等待,直到黎明:) – dognose 2014-11-08 21:47:16

3

你的三種方法是​​在同實例。並且Thread#sleep(..)不會釋放由​​獲取的鎖定。因此,執行t1的線程獲得鎖,休眠一秒鐘,喚醒,呼叫notifyAll()並完成。

然後你的兩個其他線程在執行時會輪到一個回合,然後調用wait()。但是沒有什麼可以通知他們的,所以你的應用程序會阻止。

你有一個競賽條件。改變你開始線程的順序或者像你有足夠的時間運行它,你可能會看到不同的行爲。

+0

我沒有考慮到讓t1睡1秒? – 2014-11-08 21:18:40

+0

@ db-user我會檢討。錯過了。 – 2014-11-08 21:19:57

+0

@ db-user'sleep'不釋放'synchronized'鎖。所有線程都將等待該方法調用完成。 – 2014-11-08 21:21:27

3

如果我是正確的,方法t2和t3的線程不能進入方法,因爲線程t1鎖定對象的整個時間,就像它是一個同步方法。而到了時間T2和T3實際運行notifyAll的()已經發生了,所以他們永遠等待:(

你應該嘗試啓動T2和T3,再T1。

前面已經指出。的Thread.sleep (),因爲它被標記的同步不會釋放任何鎖定或監視器所以該方法不能被其他線程進入:Thread.sleep()

相關問題