天天看點

Java面試題解析:在DCL單例寫法中為什麼要做兩次檢查?一位工作5年的小夥伴在面試的時候被問到這樣一道題:DCL的單例

作者:Tom彈架構

Java面試題解析:在DCL單例寫法中為什麼要做兩次檢查?

一位工作5年的小夥伴在面試的時候被問到這樣一道題:DCL的單例寫法中為什麼要做兩次檢查?要回答好這個問題,需要知道DCL的單例寫法以及它為什麼要這樣寫?今天給大家詳細分析一下。這道面試題的文字版我已經整理在20萬字的文檔裡面了,有需要的小夥伴可以在評論區領取。

什麼是nrl?DCL是一種單例模式寫法的簡稱,它的全稱是Double Check Lock,翻譯過來叫做雙重檢查鎖。從命名上來了解它就是兩次檢查加一把鎖。兩次檢查又是檢查什麼呢?鎖又是鎖的什麼呢?首先來看這樣一段代碼,這是一段比較标準的DCL的單例寫法。

在代碼中發現兩次檢查的判斷條件都是null==instance,而兩個檢查條件是嵌套的。在第一次檢查條件的代碼塊中加了一段synchronized代碼塊,而synchronized它就是鎖。小夥伴們應該都知道加鎖是為了去保證線程要全,而檢查是為了去保證記憶體中隻有一個執行個體。既然這兩個條件是嵌套的,那是不是可以去掉一個條件呢?下面我來詳細分析一下。

為什麼需要兩次檢查?重點來看這一個代碼片段。假設去掉第一次檢查隻保留第二次檢查。如代碼所示,現在有兩個線程T1和T2同時去通路getinstance()方法。當T1進入到synchronized代碼塊的時候T2就會阻塞,直到T1執行完成釋放CPU資源以後T2才能夠獲得鎖。

T1執行檢查條件的時候null==instance,它的條件為ture,也就是滿足條件,是以它會去建立一個新的對象。而T2執行檢查條件的時候不滿足條件就會直接傳回T1建立好的對象,這樣就保證了單例。

可是問題來了,後續如果再有其它的線程T4T5T6出現并發的時候,也會同時調用getinstance()方法。這種情況依然會出現阻塞。

相當于是不管單例對象是否已經建立,每次調用都可能出現阻塞就會影響程式的執行效率。是以加上第一次檢查的目的是保證隻有第一次出現并發的情況下才會阻塞,進而去提高性能。

再假設去掉第二次檢查隻保留第一次檢查,如代碼所示,還是線程T1、T2,同時通路getlnstance()方法,T1和T2同時滿足條件,兩個線程就會按順序來執行synchronized代碼塊中的邏輯。

假設T1先執行建立對象,T2獲得鎖的時候就依然會建立對象,而且還會覆寫T1建立的對象,這個時候就相當于是破壞了單例。是以第二次檢查的目的是為了去保證單例,避免去重複建立單例對象。

通過前面的分析可以得出結論:DCL的單例寫法中第一次檢查是為了去保證,隻有首次并發情況下才會阻塞,進而提高性能。第二次檢查是為了去保證單例,避免重複建立對象。最後加鎖當然是為了去保證線程全了。

在前面的分享中我還有一個細節沒有講到,就是在并發情況下new一個對象可能會出現指令重排的現象,這個時候就需要給聲明的單例對象加上一個volatile關鍵字來保證可見性。如代碼所示。至于沃爾沃爾格爾關鍵字為什麼能夠解決指令重排的問題,小夥伴們可以去我的首頁在往期視訊中專門有詳細分析這個問題。本期視訊就不重複講解了。

以上就是我對DCL兩次檢查的了解。我是被程式設計耽誤的文藝Tom,如果我的分享對你有幫助,請你動動手指一鍵三連分享給更多的人。關注我面試不再難。

Java面試題解析:在DCL單例寫法中為什麼要做兩次檢查?一位工作5年的小夥伴在面試的時候被問到這樣一道題:DCL的單例
Java面試題解析:在DCL單例寫法中為什麼要做兩次檢查?一位工作5年的小夥伴在面試的時候被問到這樣一道題:DCL的單例
Java面試題解析:在DCL單例寫法中為什麼要做兩次檢查?一位工作5年的小夥伴在面試的時候被問到這樣一道題:DCL的單例
Java面試題解析:在DCL單例寫法中為什麼要做兩次檢查?一位工作5年的小夥伴在面試的時候被問到這樣一道題:DCL的單例
Java面試題解析:在DCL單例寫法中為什麼要做兩次檢查?一位工作5年的小夥伴在面試的時候被問到這樣一道題:DCL的單例
Java面試題解析:在DCL單例寫法中為什麼要做兩次檢查?一位工作5年的小夥伴在面試的時候被問到這樣一道題:DCL的單例
Java面試題解析:在DCL單例寫法中為什麼要做兩次檢查?一位工作5年的小夥伴在面試的時候被問到這樣一道題:DCL的單例

繼續閱讀