[java]一個多線程引起的死鎖(class初始化,鎖)

class Init {
    
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; 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章