類初始化處理過程

前言

《Java并發變成的藝術》一書中筆者把類的初始化的處理過程分了5個階段,為了更深入的理解,我便記錄下來。

第一階段:通過在Class對象上同步(即獲取Class對象的初始化鎖),來控制類或接口的初始化。這個獲取鎖的線程會一直等待,直到當前線程能夠獲取到這個初始化鎖。

假設Class對象當前還沒有被初始化(初始化狀態state,此時被標記為state=noInitialization),且有兩個線程A和B試圖同時初始化這個Class對象。圖1是對應的示意圖。

圖1 類初始化——第1階段

表1是這個示意圖的說明。

                                  表一
時間 線程A 線程B
t1 A1:嘗試獲取Class對象的初始化鎖。這里假設線程A獲取到了初始化鎖 B1:嘗試獲取Class對象的初始化鎖,由于線程A獲取到了鎖,線程B將一直等待獲取初始化鎖
t2 A2線程A看到線程還未被初始化(因為讀取到state=noInitialization),線程設置state=initializing
t3 A3:線程A釋放初始化鎖
第2階段:線程A執行類的初始化,同時線程B在初始化鎖對應的condition上等待。

表2是這個示意圖的說明。

                                    表2
時間 線程A 線程B
t1 A1:執行類的靜態初始化和初始化類中聲明的靜態字段 B1獲取到初始化鎖
t2 B2:讀取到state=initializing
t3 B3:釋放初始化鎖
t4 B4:在初始化鎖的condition中等待
圖2 類初始化——第2階段
第3階段:線程A設置state=initialized,然后喚醒在condition中等待的所有線程。
圖3 類初始化——第3階段

表3是這個圖的說明。

                                    表3
時間 線程A
t1 A1:獲取初始化鎖
t2 A2:設置state=initialized
t3 A3:喚醒在condition中等待的所有線程
t4 A4:釋放初始化鎖
t5 A5:線程A的初始化處理過程完成
第4階段:線程B結束類的初始化處理。
圖4 類初始化——第4階段

表4是這個圖的說明。

                                      表4
時間 線程B
t1 B1:獲取初始化鎖
t2 B2:讀取到state=initialized
t3 B3:釋放初始化鎖
t4 B4:線程B的類初始化處理過程完成

線程A在第2階段的A1執行類的初始化,并在第3階段的A4釋放初始化鎖;線程B在第4階段的B1獲取同一個初始化鎖,并在第4階段的B4將之后才開始訪問這個類。根據Java內存模型規范的鎖規則,這里將如下的happens-before關系。
這個happens-before關系將保證:線程A執行類的初始化時的寫入操作(執行類的靜態初始化和初始化類中聲明的靜態字段),線程B一定能看到。

第5階段:線程C執行類的初始化的處理。
圖5 類初始化——第5階段

表5是這個圖的說明。

                                      表5
時間 線程C
t1 C1:獲取初始化鎖
t2 C2:讀取到state=initialized
t3 C3:釋放初始化鎖
t4 C4:線程C的類初始化處理過程完成

在第3階段之后,類已經完成了初始化。因此線程C在第5階段的類初始化處理過程相對簡單一些(前面的線程A和B的類初始化處理過程都經歷了兩次鎖獲取-鎖釋放,而線程C的類初始化處理過程只需要經歷一次鎖獲取-鎖釋放)。
線程A在第2階段的A1執行類的初始化,并在第3階段的A4釋放鎖;線程C在第5階段的C1獲取同一個鎖,并在第5階段的C4之后才開始訪問這個類。根據Java內存模型規范的鎖規則,將存在如下的happens-before關系。
這個happens-before關系將保證:線程A執行類的初始化時的寫入操作,線程C一定能看到。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容