2013-06-21 102 views
3

我要去通過Oracle文檔的僵局.. 我發現這個代碼這個java代碼如何產生死鎖?

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(); 
    } 
} 

我不理解,會發生什麼情況僵局?

我運行此代碼,它工作正常。所以當發生僵局時,肯定會有一些特別的事件呢?

假設首先在alphonse對象上調用弓,當在對象對象上調用bower.bowBack(this)時,它會將其鎖定在alphonse對象上嗎? 因爲如果保留其鎖定,另一個對象bow功能不會得到鎖直到alphonse離開其鎖定,這將永遠是一個死鎖情況..

+0

你是什麼意思,它運行良好,請發佈輸出,也許你只會認爲它運行良好 – AlexWien

+0

而這就是僵局! 「向我鞠躬」的信息在哪裏? – AlexWien

+0

對不起,有時它給了阿爾方斯:加斯東向我鞠躬!加斯東:阿爾方斯向我鞠躬!加斯東:阿爾方斯向我鞠躬! Alphonse:Gaston已經向我鞠躬!有時阿爾方斯:加斯東向我鞠躬!加斯頓:阿方斯向我鞠躬! – Sunny

回答

4

如果您在打印之後放了Thread.sleep(1000)第一行,在打電話給bowBack之前,你應該看到一個僵局。無論如何,這種僵局可能會發生,這將是罕見的。

您有兩個線程和兩個正在獲取的鎖是不同的命令。這可以讓每個線程持有一個鎖,但無法獲得第二個鎖。即死鎖。

注意:線程需要大量時間來啓動,這意味着第一個線程可以在第二個線程啓動之前運行完成,因此您不太可能會看到問題。


這裏是你的益智遊戲。這會造成僵局,你能看出原因嗎?

class A { 
    static final int i; 
    static { 
     i = 128; 

     Thread t = new Thread() { 
      public void run() { 
       System.out.println("i=" + i); 
      } 
     }; 
     t.start(); 
     try { 
      t.join(); 
     } catch (InterruptedException e) { 
      Thread.currentThread().interrupt(); 
     } 
    } 
+0

我看到沒有問題,除了這行Thread.currentThread()。interrupt();在catch塊?但我不明白 – Sunny

+0

有人可以解釋這個問題嗎?或者我想我將不得不將它作爲另一個問題發佈,因爲現在它讓我好奇地知道答案? – Sunny

+0

類和靜態塊的加載隱式地是「synchronized」的。這意味着當它被初始化時,你不能訪問另一個線程的類中的任何東西。在這種情況下,初始化正在等待使用'A.i'的線程,即它正在等待第一個線程完成靜態塊。 –

3

當你在處理多線程時,兩個線程中的操作可能以任何順序相對於彼此發生。所以想象這兩個演員在這種情況下執行bow,然後他們都試圖執行bow_back。由於bowbow_back正在同步,所以這兩個對象都將被鎖定,您將無法在其中任何一個上執行bow_back。這兩個對象都會等到另一個「空閒」,並且這不會發生,因爲bow在「回退」之前不會返回。

0

在弓A和G結束時調用bowBack,導致從A和G中調用一個G.bow,而A和G的弓同步。所以他們都等待對方完成。

4

你有2個對象,阿方斯和加斯東和2個線程,線程1和線程

假設出現這種情況:

  1. 線程1:阿方進入弓()方法。並將鎖定alphonse物體

  2. 線程2:gaston進入bow()方法。並且將對gaston對象鎖定

  3. 線程1:alphonse在bow()方法中,在gaston對象上調用bowBack()。

    - >線程1將阻止,因爲線程2已經擁有加斯

  4. 鎖定線程2:加斯而在船頭()方法,調用阿爾對象上bowBack()。

    - >線程2將阻止,因爲線程1已經對阿方

所以現在線程1正在等待線程2鎖。而Thread2正在等待Thread1。這是一個僵局。

1

如果雙方在同一時間進入bow()方法會發生的dealock,或在

System.out.println(); 

如果你沒有看到這兩個的「已鞠躬還給我!」消息,然後發生死鎖!

如果第一個線程在第二個線程開始之前終止,則不會發生死鎖。

用Thread.sleep(1000)擴展代碼;

public synchronized void bow(Friend bower) { 
System.out.println(....); 
Thread.sleep(1000); 
... 
} 

然後這兩個線程輸入弓()和dealock將發生。