2012-10-21 109 views
1

請問有人能解釋爲什麼這段代碼是死鎖。它似乎應該正常工作。請詳細解釋它。謝謝。Java中的多線程死鎖

public class H extends Thread { 
    String info = ""; 
    public H (String info) { 
     this.info = info; 
    } 

    public synchronized void run() { 
     try { 
      while (true) { 
       System.out.println(info); 
       notify(); 
       wait(); 
      } 
     } catch (Exception e) {} 

    } 
    public static void main(String[] args) { 
      new H("0").start(); 
      new H("1").start(); 
    } 

}

+0

它究竟是如何死鎖?它打印兩個東西,但沒有終止? –

+0

它打印而這就是卡在死鎖 –

回答

5

每個線程同步上this(經由​​關鍵字上的方法),這是用於兩個線程對象的不同。他們每個呼叫notifywait但他們不相互作用,因爲this是不同的。因此,在第一次迭代中,他們都撥打wait並永遠阻止,因爲沒有人會將其喚醒。

以下是我爲使代碼正常工作而進行的一些更改。注意共享靜態字段,允許線程進行通信:

public class Test extends Thread { 
    String info = ""; 
    static final Object signal = new Object(); 
    static volatile String current = null; 

    public Test (String info) { 
     this.info = info; 
    } 

    public void run() { 
     try { 
      synchronized(signal) { 
       while (true) {         
        while(current.equals(info)) 
         signal.wait(); 
        System.out.println(info); 
        current = info; 
        signal.notify(); 
       } 
      } 
     } catch (Exception e) {} 

    } 

    public static void main(String[] args) { 
     Test.current = "0"; 
     new Test("0").start(); 
     new Test("1").start(); 
    } 
} 

有你原來的代碼,我想讓其他一些注意事項:

  • 你應該努力實現的,而不是延長ThreadRunnable 。這樣給你更多的靈活性。
  • 不要吞下異常。
+0

+1因爲這就是爲什麼他們永遠不會完成,但這並非真正的死鎖。當兩個資源都被阻塞等待另一個資源完成時,就會出現死鎖。這只是兩個永久等待的資源。它是'while(true){}'的線程停放版本。 – yshavit

1

notify()只喚醒當前正在等待對象的線程。當你調用notify()時,任何情況下都不會有線程在等待。然後,當你呼叫等待時,你永遠不會有任何通知()的代碼。基本上,你不能從同一個線程通知一個線程,因爲它必須等待。嘗試通過等待一段時間後從主線程通知他們,看看會發生什麼。

public class H extends Thread { 
    String info = ""; 
    public H (String info) { 
     this.info = info; 
    } 

    public synchronized void run() { 
     try { 
      while (true) { 
       System.out.println(info); 
       wait(); 
      } 
     } catch (Exception e) {} 

    } 
    public static void main(String[] args) throws Exception { 
      H a = new H("0").start(); 
      H b = new H("1").start(); 
      Thread.sleep(1000); 
      a.notify(); 
      b.notify(); 
    } 
} 

請注意,這兩個線程都不會通知其他線程。等待對象只能等待它,而不是完全等級。

TL; DR:notify()沒有做任何事,wait()創建死鎖。

3

notifywait都呼籲Thread對象這是不同的,所以當一個線程到達wait,其他線程不會通知它,相反,每個線程通知本身。

的流動是非常(有可能是交織):

  1. 的ThreadA開始
  2. 的ThreadA通知了正在上ThreadA中的鎖等待的對象
  3. 的ThreadA上ThreadA中的鎖等待
  4. ThreadB開始
  5. ThreadB通知等待ThreadB鎖的對象
  6. ThreadB在ThreadB的鎖上等待

最終狀態 - 兩個線程正在等待,沒有人通知他們。