我跑進我的應用程序的一些鎖定問題,其中包括像下面幾類:靜態初始化和靜態同步方法鎖定問題
public interface AppClient {
void hello();
}
public class Client implements AppClient {
public synchronized static AppClient getInstance() {
return instance;
}
public void hello() {
System.out.println("Hello Client");
}
private final static class InnerClient implements AppClient {
public void hello() {
System.out.println("Hello InnerClient");
}
}
private static AppClient instance;
static {
instance = new InnerClient();
doSomethingThatWillCallClientGetInstanceSeveralTimes();
}
}
public class Application {
new Thread() {
AppClient c = Client.getInstance();
c.hello();
}.start();
new Thread() {
AppClient c = Client.getInstance();
c.hello();
}.start();
// ...
new Thread() {
AppClient c = Client.getInstance();
c.hello();
}.start();
}
在doSomethingThatWillCallClientGetInstanceSeveralTimes()方法,它會做相當多的初始化涉及很多類的工作,並且在初始化期間多次循環調用Client.getInstance靜態方法(我理解這並不好,但是,這是一個持續20多年的遺留代碼庫)。
這裏是我的問題:
1)我認爲類客戶端初始化完成之前,只觸發類初始化客戶端可以訪問Client.getInstance方法,因爲JVM將Client.class對象上進行同步的第一個線程在類初始化完成之前。我閱讀了關於相關主題的JLS並得出了這個結論(第12.4.2節,詳細初始化過程,http://java.sun.com/docs/books/jls/third_edition/html/execution.html)。
2)但是,這不是我在真實環境中看到的行爲。例如,有三個線程調用Client.getInstance(),線程1觸發Client.class初始化,並在doSomethingThatWillCallClientGetInstanceSeveralTimes()方法中多次調用Client.getInstance()。並且在完成doSomethingThatWillCallClientGetInstanceSeveralTimes()方法之前,線程2獲取Client.class對象的鎖定(這怎麼可能?但它確實發生了),並且進入Client.getInstance方法(因爲此方法是靜態同步方法) 。出於某種原因,線程2不能返回「實例」(我猜它正在等待Client.class完成其初始化)。同時,thread-1無法繼續,因爲它仍然需要在doSomethingThatWillCallClientGetInstanceSeveralTimes()中調用Client.getInstance,並且由於它由線程2擁有,所以無法獲取該鎖。線程轉儲告訴我,線程2處於RUNNABLE狀態,線程1處於BLOCKED狀態,等待線程2擁有的鎖。
我只能在Windows中的64位Java 6u23 JVM中重現此行爲,無法將其重現爲32位Java 6 JVM + Windows環境。有人能告訴我我在這裏錯過了什麼嗎?這樣的代碼註定會引起這種鎖定,如果是的話,怎麼會來?我對這部分的JLS理解是不正確的?或者這是一個JVM問題?任何幫助表示讚賞。謝謝。
你的代碼有點令人困惑,特別是當Client和InnerClient實現AppClient時 - 我看不出客戶需要什麼。如果你可以創建一個簡短但完整的程序來演示這個問題,那將會有很大的幫助。 – 2011-01-06 07:01:56
@Jon我無法創建一個簡單的程序來重現此問題。上面的程序是我從一個巨大的庫中提取的骨架代碼,我認爲問題在於此。這是因爲向後可比較性,Client和InnerClient實現AppClient,並且我不想錯過任何重要信息成爲這個問題的原因,所以我列在那裏。也許我需要更準確的時機和更多的運氣來用簡單的程序來演示這個問題,無論如何,我只會發現我列出的當前程序的行爲將像上面提到的那樣。 – nybon 2011-01-06 07:20:44
那麼我會專注於以受控的方式重現它 - 因爲如果沒有這個,我們真的只是在猜測。正如你所說,它聽起來像*應該*工作... – 2011-01-06 07:22:53