2012-12-11 89 views
0

雖然通過SCJP6的考試成績單,我發現這樣的問題:此代碼如何導致死鎖?

class Clerk implements Runnable { 

    private Record A, B; 

    public Clerk(Record a, Record b) { 
     A = a; 
     B = b; 
    } 

    public void run() { 
     while(true) { 
      doStuff(A, B); 
     } 
    } 

    public synchronized void doStuff(Record a, Record b) { 
     synchronized(a) { 
     synchronized(b) { 
      a.add(1); 
      b.add(-1); 
     }} 
    } 

} 

然後

Record a = new Record(); 
Record b = new Record(); 

new Thread(new Clerk(a, b)).start(); 
new Thread(new Clerk(a, b)).start(); 

回答說,這個代碼可以事業僵局,但我不明白 - 究竟是怎麼那可能嗎?有人可以幫我弄清楚嗎?

+3

這是不可能的。這些字段被稱爲'A'和'B',但'run()'使用'a'和'b',所以代碼甚至不會編譯。 :) – Ryan

+2

在我看來,代碼不會死鎖,但是當你在第二個構造函數中調用a和b時,它可能(也很可能會)(假設你修復了@minitech注意到的問題) –

+0

對不起,沒有正確複製問題:)現在它編譯 –

回答

9

除了它沒有編譯的事實之外,該代碼中沒有死鎖。此代碼絕對可以創建一個僵局:

new Thread(new Clerk(a, b)).start(); 
new Thread(new Clerk(b, a)).start(); 

因此,如果問題是:可以在Clerk類是僵局的根源?那麼答案是肯定的。

編輯

短的例子,應該死鎖較快。如果在原始問題中使用a和b,則程序運行良好。

public class Test1 { 

    public static void main(String[] args) { 
     Record a = new Record(); 
     Record b = new Record(); 

     new Thread(new Clerk(a, b)).start(); 
     new Thread(new Clerk(b, a)).start(); 
    } 

    static class Record { 
    } 

    static class Clerk implements Runnable { 

     private Record A, B; 

     public Clerk(Record a, Record b) { 
      A = a; 
      B = b; 
     } 

     public void run() { 
      while (true) { 
       System.out.println("in thread " + Thread.currentThread()); 
       for (int i = 0; i < 10000; i++) { 
        doStuff(A, B); 
       } 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException ex) { 
       } 
      } 
     } 

     public synchronized void doStuff(Record a, Record b) { 
      synchronized (a) { 
       synchronized (b) { 
       } 
      } 
     } 
    } 
} 
+2

+1我懷疑這個問題已被錯誤地複製到某個地方。 –

+0

爲什麼顛倒這個論點會導致死鎖? –

+2

@LewsTherin:可以鎖定'a',然後才能鎖定'b',另一個已經有,但正在等待'a'。 – Ryan

3

我認爲這會死鎖,如果一個線程是用a/b構造的,第二個用b/a構造的。

在這種情況下,線程會鎖定第一個實體,然後鎖定第二個實體。如果線程1鎖定了a並試圖鎖定b,並且線程2同時鎖定了b並等待a,那麼它將全部停止。

以下是Java tutorial deadlock example,與上例非常相似。