2011-04-26 90 views
6

我在java類中有兩個方法,它們都有一個使用同一對象進行同步的代碼塊。我明白,在JAVA同步方案中,線程獲取的鎖是可重入的。有了這個我可以安全地說下面的一段代碼不會在所有情況下導致任何問題?使用同步語句的可重入同步行爲

public class Someclass 
{ 
    private static final Object LCK_OBJ = new Object(); 
    //..... 

    publc void method1() 
    { 
    //some code.... 
    synchronized(LCK_OBJ) 
    { 
     //some sychronized code. 
     method2(..); 
    } 
    //some more code.... 
    } 

    protected static final void method2(..) 
    { 
     Someclass ref = null; 
     //some code which gets different other references of SomeClass in a loop.... 
     ref.method3(..); 
    } 

    publc void method3() 
    { 
    //some code.... 
    synchronized(LCK_OBJ) 
    { 
     //some sychronized code. 
    } 
    //some more code.... 
    } 

}//end of class  

回答

5

是的,你可以,但是這段代碼不會編譯:你正在從一個靜態方法「method2」調用實例方法「method3」。除此之外:如果一個線程設法獲得「method1」中的鎖,如果仍然有「method3」中的鎖。

+0

謝謝Tomasz Stanczak!在輸入示例代碼時,我錯過了通過對象引用鍵入實例方法調用的方法。請耐心等待並答覆答覆。只要添加到我以前的查詢中,當某個線程當前在method2內執行(從method1調用)時,如果某個其他線程試圖執行方法1或方法3中的同步代碼,我們可以肯定地說第二個線程將被阻塞,直到第一個線程完成執行方法1,方法2和方法3? – Muthu 2011-04-26 19:00:59

+0

是的,它會阻塞,直到釋放鎖,並且當第一個線程從method3和method2返回後離開方法1中的同步塊時會發生這種情況。 – 2011-04-27 06:47:00

4

是的,同一個線程可以在同一個鎖上多次輸入​​塊。注意不要以不同順序獲取其他鎖,否則可能導致死鎖。

8

是的,同步塊是可重入的。 ReentrantLock也是可重入的,如果你想自己對塊進行編碼,你可能想要使用它,因爲它具有更多的靈活性/功能性。

我會確保任何鎖final如果鎖定對象不能是最終的,那麼幾乎可以肯定的錯誤(或混亂的根源)

出於比較的目的,而不是在Java中所有的鎖都折返。 FileLock不是因爲它直接將請求傳遞給操作系統。

+0

@Stephen C,我的觀點是您可以相信Java中的所有鎖都是可重入的。 – 2011-04-26 08:58:57

+0

@Stephen C,夠了。 – 2011-04-26 15:30:24

+0

感謝您對此行爲的確認。在最後一個修飾語中,你是對的......這實際上是我在輸入示例代碼時錯過了它的部分,儘管我的意思是(注意全部大寫變量名)。對不起,再次感謝。 – Muthu 2011-04-28 19:04:35

0

儘管這段代碼不會像前面提到的那樣編譯,但我們考慮一下method2不是靜態的情況。從method1到method2再到method3的調用是重入同步的一個很好的例子。當一個線程啓動時,它會創建一個新的堆棧run()放在堆棧底部。由於對method1的調用來自run(),所以它被添加到run()之上的堆棧中,然後進入堆棧中的method2和method3。此外,由於對象鎖由方法2在堆棧上執行,鎖在所有調用的同步API上保留。鎖的釋放通過展開堆棧中最頂端的方法(本例中爲method3)開始,直到實際的api到達哪個調用同步。