2010-02-16 53 views
6

下面是直接來自Sun教程描述死鎖的代碼。然而,我不明白在這種情況下死鎖是如何發生的,因爲這兩種方法都是同步的。兩個線程如何同時在同一個同步方法中?關於來自太陽的死鎖教程的問題

死鎖描述了一個情況,其中兩個或多個線程永遠被阻塞,彼此等待。這是一個例子。

阿爾方斯和加斯頓是朋友,並且是禮貌的好信徒。嚴格的禮貌規則是,當你向朋友鞠躬時,你必須保持鞠躬,直到你的朋友有機會歸還弓。不幸的是,這條規則沒有考慮到兩個朋友可能同時向對方低頭的可能性。這個示例應用程序,死鎖,模型這種可能性:

public class Deadlock { 
    static class Friend { 
     private final String name; 
     public Friend(String name) { 
      this.name = name; 
     } 
     public String getName() { 
      return this.name; 
     } 
     public synchronized void bow(Friend bower) { 
      System.out.format("%s: %s has bowed to me!%n", 
        this.name, bower.getName()); 
      bower.bowBack(this); 
     } 
     public synchronized void bowBack(Friend bower) { 
      System.out.format("%s: %s has bowed back to me!%n", 
        this.name, bower.getName()); 
     } 
    } 

    public static void main(String[] args) { 
     final Friend alphonse = new Friend("Alphonse"); 
     final Friend gaston = new Friend("Gaston"); 
     new Thread(new Runnable() { 
      public void run() { alphonse.bow(gaston); } 
     }).start(); 
     new Thread(new Runnable() { 
      public void run() { gaston.bow(alphonse); } 
     }).start(); 
    } 
} 

死鎖時運行,這是非常有可能的是,當他們嘗試調用bowBack兩個線程將被阻塞。這兩個塊都不會結束,因爲每個線程都在等待另一個線程退出低頭。

+1

可能重複的[嘗試包裹我的周圍大​​腦如何線程死鎖](http://stackoverflow.com/questions/749641/trying-to-wrap-my-wee-brain-around-how-threads-deadlock ) –

回答

7

同步(實例)方法鎖定對象,而不鎖定類。

alphonse.bow抓住alphonse和gaston.bow上的鎖來抓住gaston上的鎖。當'alphonse'線在弓中時,它會嘗試在bower.bowBack上抓住'gaston'上的鎖。同樣,'gaston'試圖抓住'alphonse'的鎖。

編輯爲清楚(我希望):

讓我們把兩個線程線程1和線程。

Thread1運行alphonse.bow(gaston),它在此抓取alphonse對象上的鎖,而Thread2運行gaston.bow(alphonse)並抓取gaston對象上的鎖。

在Thread1中,當它試圖運行bower.bowBack(this),其中bower = gaston時,該線程需要首先獲取gaston上的鎖。

當這種情況發生時,Thread2試圖用bower = alphonse做同樣的事情。 Thread1有一個Thread2需要的鎖,反之亦然,這就是發生死鎖的原因。

順便說一下,並不總是會發生死鎖。如果Thread1可以在Thread2有機會完成之前開始和完成(例如,如果在Thread1啓動後但在創建/啓動Thread2之前掛起主線程),則不會發生死鎖。

+0

alphonse如何試圖鎖定gaston。 alphonse總是使用alphonse實例。 – jax

+0

我不明白以下內容:「當'alphonse'線頭處於弓形時,它會試圖抓住bower.bowBack上'gaston'的鎖。」 'alphonse'如何試圖鎖定gaston實例。 – jax

+0

第一個線程調用alphonse.bow(gaston)。此時,線程對alphonse有鎖定。一旦該方法歸結爲bower.bowBack,那裏的bower就是gaston,它會嘗試獲得gaston的鎖定。 'alphonse',我的意思是運行'alphonse.bow(gaston)'的線程;'alphonse.bow(gaston)','alphonse.bow'對不起,如果不清楚。 –