2014-10-29 102 views
2

請參考下面的代碼爲什麼它不會造成死鎖?

package com.test; 

public class DeadLock { 

    private void method1() { 

     synchronized (Integer.class) { 
      method2(); 
     } 
    } 

    private void method2() { 
     synchronized (Integer.class) { 
      System.out.println("hi there"); 
     } 
    } 

    public static void main(String[] args) { 
     new DeadLock().method1(); 
    } 
} 

按我的理解,在method2代碼不應該在任何情況下執行,因爲method1持有Integer.classmethod2嘗試鎖再次訪問Integer.class鎖。但令我驚訝的是,代碼運行良好,它向控制檯輸出「hi there」。有人可以澄清嗎?

+1

互動(遞歸)互斥?在這種情況下,互斥鎖可以從同一個線程獲取多倍的時間,但會從多個線程中(死鎖)鎖定 – 2014-10-29 11:11:59

+0

爲什麼你認爲它應該死鎖?它直截了當的不是嗎? – SMA 2014-10-29 11:13:33

+0

如果您只有一個線程,則無法獲取鎖定。 – Leonidos 2014-10-29 11:17:23

回答

4

鎖由線程所有。如果你的線程已經擁有一個鎖,那麼Java假定你不需要再次獲取它並繼續。

,如果你在method1()開始線程在佔用鎖和第二個線程執行方法method2()你會得到一個僵局。

如果你喜歡的代碼,然後​​是這樣的:

Lock lock = Integer.class.getLock(); 
boolean acquired = false; 
try { 
    if(lock.owner != Thread.currentThread()) { 
     lock.acquire(); 
     acquired = true; 
    } 

    ...code inside of synchronized block... 
} finally { 
    if(acquired) lock.release(); 
} 

這裏是代碼演示了僵局。只需設置runInThreadtrue

package com.test; 

public class DeadLock { 

    private void method1() { 

     synchronized (Integer.class) { 
      boolean runInThread = false; 

      if(runInThread) { 
       Thread t = new Thread() { 
        @Override 
        public void run() { 
         method2(); 
        } 
       }; 
       t.start(); 
       try { 
        t.join(); // this never returns 
       } catch(InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } else { 
       method2(); 
      } 
     } 
    } 

    private void method2() { 
     System.out.println("trying to lock"); 
     synchronized (Integer.class) { 
      System.out.println("hi there"); 
     } 
    } 

    public static void main(String[] args) { 
     new DeadLock().method1(); 
    } 
} 
+0

嗯,我懷疑它。實際上我想說的是,如果method1()獲取自身的鎖定,那麼所有其他線程將處於等待狀態na? – Krishna 2014-10-29 11:20:09

+0

對於像我這樣的新鮮人來說,它的一點點沉重的解釋:D哈哈反正+1正確答案。 – Krishna 2014-10-29 11:27:21

+0

無論多少個線程調用method1(),都不會有死鎖。爲了發生死鎖,程序必須至少有兩個鎖。當某些線程集的每個成員持有一個鎖並且阻止等待獲取由其中一個成員持有的鎖時發生死鎖。在最簡單的情況下,線程1持有鎖A,並在嘗試獲取鎖B時被阻塞。同時,線程2阻止了鎖B,嘗試獲取鎖A時線程2被鎖定。在這種情況下,兩個線程都無法做到任何進展。 – 2014-10-29 17:29:21

0

你的代碼就相當於:

synchronized (Integer.class) { 
    synchronized (Integer.class) { 
     System.out.println("hi there"); 
    } 
} 

如果線程獲取鎖,進入第一​​塊它不會有任何問題訪問第二

爲了產生死鎖,對method2的調用應該由不同的線程執行。

+0

您不能僅使用一個鎖對象創建死鎖。看到我對Aaron Digulla的回答的評論。 – 2014-10-29 17:40:11

3

看來你誤解了這個概念。 方法永遠不會獲取鎖,在同步方法的情況下,調用該方法的實例用作鎖,並且在同步塊的情況下線程獲取指定對象上的鎖。

這裏實例獲取Integer.class上的鎖,然後繼續執行method2。

不存在死鎖情況,因爲在您的情況下線程繼續執行您在method1內調用的方法。所以沒有發生死鎖。

+1

+1其正確:) – Krishna 2014-10-29 11:26:37

+1

@克里希納感謝您的編輯和upvote。 – EMM 2014-10-29 11:28:31

+0

實例不獲取lock.Lock將被執行它的線程獲取。 – aniugne 2014-10-29 11:45:02

0
synchronized (Integer.class) { 
      method2(); 
     } 
當你調用這個 method2();那麼它不給鎖定任何種類的

mehtod其繼續去您調用手段這個方法。

private void method2() { 
     synchronized (Integer.class) { 
      System.out.println("hi there"); 
     } 
    } 

並完成其返回。所以沒有死鎖的情況。希望這個解釋有幫助。

0

如前所述,當沒有其他線程已經阻止它時,一個線程可以訪問多個同步塊。在這種情況下,同一個線程可以重新輸入同步塊,因爲它已經從method1中保持它。

爲了導致死鎖,您必須至少使用兩個線程和兩個不同的鎖。它必須以相反的順序訪問兩個鎖。看看代碼:

private void method1() throws InterruptedException 
{ 
    synchronized (Integer.class) 
    { 
     System.out.println(Thread.currentThread().getName() + " hi there method 1"); 
     Thread.sleep(1000); 
     method2(); 
    } 
} 

private void method2() throws InterruptedException 
{ 
    synchronized (Double.class) 
    { 
     System.out.println(Thread.currentThread().getName() + " hi there method 2"); 
     Thread.sleep(1000); 
     method1(); 
    } 
} 

public static void main(String[] args) throws InterruptedException 
{ 
    new Thread() 
    { 
     @Override 
     public void run() 
     { 
      try 
      { 
       new DeadLock().method1(); 
      } 
      catch (InterruptedException e) 
      { 
       e.printStackTrace(); 
      } 
     } 
    }.start(); 
    new DeadLock().method2(); 
} 
+1

我認爲這個解決方案必須非常簡短,並且很容易理解。 – Krishna 2014-10-29 11:31:13

+1

當你使用java的線程時,解決方案永遠不會這樣。但我已經掌握了,所以下次會盡我所能。 – 2014-10-29 12:03:52

+0

好祝你好運。 – Krishna 2014-10-29 12:34:59