2010-03-10 31 views
2

使用以下代碼,如果線程調用LoggingWidget.doSomething(), 線程必須經過的鎖定獲取順序是什麼? (即不上算LoggingWidget鎖定,然後再沾到工具?鎖)鎖定採集訂單

public class Widget { 
    public synchronized void doSomething() { 

    } 
} 

public class LoggingWidget extends Widget { 
    public synchronized void doSomething() { 
     System.out.println(toString() + ": calling doSomething"); 
     super.doSomething(); 
    } 
} 

回答

2

鎖在這種情況下是this所以只有一個鎖,即是實例。如果有多個實例,則每個實例都具有完全獨立的鎖,無論它是否爲WidgetLoggingWidget

讓我換一種方式。您的代碼在語義上等同於:

public class Widget { 
    public void doSomething() { 
    synchronized (this) { 
     // do stuff 
    } 
    } 
} 

public class LoggingWidget extends Widget { 
    public void doSomething() { 
    synchronized (this) { 
     System.out.println(toString() + ": calling doSomething"); 
     super.doSomething(); 
    } 
    } 
} 

只調用其中一種方法,因此只有一個鎖。

+0

最後一句話是錯的恕我直言。無論您是否擁有LoggingWidget或Widget,doSomething()中都只有一個'this'。 – 2010-03-10 10:22:16

+0

是的,如果你在這兩種方法中調用'System.identityHashCode(this)',你將得到相同的值 – 2010-03-10 10:54:41

1

在Java中,它們是caleld監視器,並且是每個對象。在你的例子中,只有一個監視器。

0

如果你想確保你得到類型LoggingWidget的正確的鎖,而不是Widget的你可以這樣做:

public class LoggingWidget extends Widget { 
    private final Object readLock = new Object(); 

    public void doSomething() { 
    synchronized (readLock) { 
     System.out.println(toString() + ": calling doSomething"); 
     super.doSomething(); 
    } 
    } 
} 

或者,如果你使用Lombok你可以只寫

public class LoggingWidget extends Widget { 
    @Synchronized("readLock") 
    public void doSomething() { 
    System.out.println(toString() + ": calling doSomething"); 
     super.doSomething(); 
    } 
} 
0

有隻有一個鎖bcoz只有一個對象,但如果調用了子類對象的doSomething()方法,則會獲取同一個鎖兩次。在JVM中,所有者(線程)是相同的,但它將收購計數設置爲兩個每次擁有線程存在同步塊時,獲取計數遞減。所以在這裏,當鎖最終被釋放時,它會減少兩次到零,每個同步塊一個。