2014-01-26 68 views
1

我在試圖弄清楚下面的代碼如何工作時遇到一些問題。在輸出中,我得到所有線程都表示他們很睏倦,然後Thread-1或Thread-0喚醒並且程序凍結。這些睡眠線程是如何工作的?

我知道Thread-1或Thread-0會被喚醒,因爲threads[5]調用了notify()函數,所以wait-set中的第一個線程會恢復生機。但是...如果threads[5]中的線程被阻止,因爲wait()被調用,它怎麼可能仍然調用wakeUp()函數?

如果以某種方式它可以調用方法爲什麼wakeUpAll()函數不起作用?如果我睡主線,爲什麼它能工作?

public class SleepingThreads extends Thread 
{ 
    Object lock; 

    public SleepingThreads(Object l) { lock=l; } 

    public void run() 
    { 
     System.out.println(this.getName()+" said: I am sleepy..."); 
     synchronized(lock) 
     { 
      try { lock.wait(); } catch (InterruptedException e){} 
      System.out.println(this.getName()+" said: but now I woke up..."); 
     } 
    } 

    public void wakeUp() { synchronized (lock) { lock.notify(); } } 

    public void wakeUpAll() { synchronized (lock) { lock.notifyAll(); } } 

    public static void main(String[] args) throws InterruptedException 
    { 
     Object lock = new Object(); 
     SleepingThreads[] threads = new SleepingThreads[10]; 

     for (int i=0; i<10;i++) 
     { 
      threads[i] = new SleepingThreads(lock); 
      threads[i].start(); 
     } 

     threads[5].wakeUp(); 
     //currentThread().sleep(200); 
     threads[5].wakeUpAll(); 

     System.out.println("Done."); 
    } 
} 
+0

我想我應該至少得到一個投票,我試圖告訴你,主線程是執行.. =) –

+1

一般原理:如果你有一個沒有時間週期的「等待」來檢查一個條件,你(幾乎)肯定會有一個等待發生的錯誤。 – Voo

+0

謝謝!我需要點數。 –

回答

1

兩件事情:

  1. wakeUp()wakeUpAll()方法被調用的threads[5]實例,但不是其執行線程。它們正在調用主線程線程。因此即使threads[5]線程處於睡眠狀態,也可以調用它。

  2. main必須睡200ms的原因是因爲如果不是這樣,一些線程(那些不說「但現在我醒來」的線程尚未啓動,當您撥打wakeUpAll() (即,他們沒有執行run尚未方法,或者他們還沒有練到lock.wait()尚未)。因此出現notifyAll()他們稱之爲lock.wait()之前,他們的等待後,從來沒有收到通知。

+0

好吧,只有幾個人說,他們醒來是因爲他們甚至在進入等待期之前得到通知? – dabadaba

+0

是的,那些說「但現在我醒來」的人在wakeUpAll()被調用之前等待。 wakeUpAll()被調用後,不說「但現在我醒了」的那些人。線程執行順序並不總是可預測的。 –

0

線5不是要求.wakeUp(),主線程調用.wakeUp()

+0

如果他們都死了'run()'方法完成?因爲它確實:所有線程都說他們醒了。無論如何,這個答案並不能解釋我觀察到的行爲。 – dabadaba

+0

爲什麼主線程成功調用wakeUp()而不是'wakeUpAll()'? – dabadaba

+0

看到我的答案,main會成功調用wakeUpAll(),並在鎖上執行notifyAll(),但是這發生在某些線程正在等待鎖之前。所以那些wakeUpAll()被調用後等待的線程永遠不會看到notifyAll()。 –