關於單例設計模式中的雙重判斷的理解和分析
之前在很多地方看到過這種單例的實現,但是對其中的兩個if判斷的作用不理解。今天就詳細的解釋一下:
class SingletonTwo{ /* 持有私有靜態例項,防止被引用,此處賦值為null,目的是實現延遲載入 */ private static SingletonTwo instance = null; /* 私有構造方法,防止被例項化 */ private SingletonTwo(){ } public static SingletonTwo getInstance() { //位置1 if (instance == null) { //位置2 synchronized (instance) { //位置3 if (instance == null) { //位置4 instance = new SingletonTwo(); } } } return instance; } }
假設執行緒A和B作為第一批呼叫者同時或幾乎同時呼叫靜態工廠方法getInstance。
1)因為A和B是第一批呼叫者,當它們進入靜態工廠方法時,instance變數是null。因此它們幾乎同時到達 位置2。
2) 假設A執行緒先進入 synchronized (instance),到達位置3,這時由於同步機制,執行緒B無法到達位置3,只能在位置2等待。
3)執行緒A執行instance = new SingletonTwo()語句,使得instance引用指向一個物件。此時執行緒B還在位置2上等待。
4)執行緒A退出synchronized (instance),返回SingletonTwo物件,退出靜態工廠方法。
5)執行緒B進入 synchronized (instance)塊,達到位置3,此時instance已經不為null,因此執行緒B退出synchronized (instance),
返回SingletonTwo物件(執行緒A所建立的SingletonTwo物件),退出靜態工廠方法。
到此為止,執行緒A和B得到同一個SingletonTwo物件。
第一個if判斷的作用:是為了提高程式的 效率,當SingletonTwo物件被建立以後,再獲取SingletonTwo物件時就不用去驗證同步程式碼塊的鎖及後面的程式碼,直接返回SingletonTwo物件
第二個if判斷的作用:是為了解決多執行緒下的安全性問題,也就是保證物件的唯一。如果沒有第二個if判斷,在上面介紹的步驟5處,執行緒B進入synchronized (instance)塊,不用去驗證instance是否為null,就會直接建立一個SingletonTwo新物件,這樣整個程式執行下來就有可能建立多個例項。