static volatile boolean done = false;
static {
new Thread() {
public void run() {
System.out.println("enter thread");
done = true;
}
}.start();
while (!done)
;
}
public static void main(String[] args) {
System.out.println("Finished");
}
}
輸出“enter thread”後死循環。
這個小程序不會終止。其主線程會陷入死循環,那個單獨的線程會永遠等待。爲方便起見,稱主線程爲M,單獨的線程爲N。代碼的執行過程大體如下:
1. M看到類Init, 獲取Init.class上的鎖,判斷初始化是否正在進行,或着已完成。
2. 此時初始化既未進行,也未完成,於是M設一個標誌表示初始化正在進行,然後釋放Init.class上的鎖
3. M開始初始化類Init, 完成對Init.done的初始化
4. M進入static塊,啓動N, 進入while循環
5. N開始運行,打印出"enter thread",
6. N看到Init.done, 這是N第一次看到類Init, 所以像M一樣,試圖初始化Init。
7. 與步驟1類似,N 成功獲取Init.class上的鎖
8. N發現M所設的初始化正在進行的標誌,N就釋放Init.class的鎖,並進入等待狀態。
9. 由於N在等待,Init.done一直爲false,M就一直在while中循環,不能退出static塊.
10. 由於M對Init的初始化不能完成,所以N不能得到M的通知而退出等待。
可見,這是一個M和N的死鎖問題。
一般而言,只要N引用類本身或類的成員,包括任何method或field,N都會先去初始化這個類從而陷入死鎖。
但是有例外,例如如果N引用的是一個常變量(constant variable),N 就不會去初始化這個類,例如如果Init有以下成員, 引用它就可以。
final boolean ok = false;
還有一個例外,以下語句出現在run()中也不會引發Init的初始化.
Init C = null;