單例模式Double Checked

2021-09-01 05:11:05 字數 2710 閱讀 5943

這裡主要用double-checked和volatile實現單例模式 (雙重檢查鎖定模式)

dcl單例模式: 懶漢式套路基礎上加入併發控制,保證在多執行緒環境下,對外存在乙個物件

1、構造器私有化 -->避免外部new構造器

2、提供私有的靜態屬性 -->儲存物件的位址

3、提供公共的靜態方法 --> 獲取屬性

public class doublecheckedlocking 

//3、提供公共的靜態方法 --> 獲取屬性

public static doublecheckedlocking getinstance()

synchronized(doublecheckedlocking.class)

}return instance;

}public static doublecheckedlocking getinstance1(long time) catch (interruptedexception e)

instance = new doublecheckedlocking();

//1、開闢空間 //2、初始化物件資訊 //3、返回物件的位址給引用

}return instance;

}public static void main(string args) ) ;

t.start();

system.out.println(doublecheckedlocking.getinstance());}}

這種方式稱為延遲初始化,但是在多執行緒的情況下會失效,於是使用同步鎖,給getinstance() 方法加鎖:

public static synchronized doublecheckedlocking getinstance() 

return instance;

}

同步是需要開銷的,我們只需要在初始化的時候同步,而正常的**執行路徑不需要同步,這裡加入雙重檢查加鎖(dcl)

這樣一種設計可以保證只產生乙個例項,並且只會在初始化的時候加同步鎖,看似精妙絕倫,但卻會引發另乙個問題,這個問題由指令重排序引起。指令重排序是為了優化指令,提高程式執行效率。指令重排序包括編譯器重排序和執行時重排序。jvm規範規定,指令重排序可以在不影響單執行緒程式執行結果前提下進行。

如何避免呢?加入volatile

在我們new乙個物件的時候會做三件事情,1、開闢空間 2、初始化物件資訊 3、返回物件的位址給引用,如果有構造器在哪初始化得過程中或者耗時較慢的情況下,就有可能先於第2步將物件的位址值給了引用,造成結果可能會遇到這種情況:a執行緒正在初始化這個物件,這時候b執行緒已經拿到了這個引用,b執行緒拿出的物件值就有可能是個空的物件

如何避免指令重排呢?

在jdk1.5之後,可以使用volatile變數禁止指令重排序,讓dcl生效:

如果沒有和同步,會存在不一致的情況

public static doublecheckedlocking getinstance1(long time)  catch (interruptedexception e) 

instance = new doublecheckedlocking();

//1、開闢空間 //2、初始化物件資訊 //3、返回物件的位址給引用

如果加入同步,結果一樣

//3、提供公共的靜態方法 --> 獲取屬性

單例模式 DoubleCheck

1.單例模式理解 是為了滿足一些場景,乙個物件只能建立乙個例項物件的場景。流程 1.構造方法私有化,2.宣告物件 位靜態 3.類方法返回例項化後的物件。2.將單例模式分為兩類 懶漢式和餓漢式 懶漢式 特點在定義singleton是就new public class singleton public ...

單例模式與double check

本文主要是講double check,通常double check比較少用,一般是在高併發的情況下。但是建議大家寫單例的時候都用上。單例模式分兩種 餓漢式與懶漢式,餓漢式是指在類載入時就進行例項化,而懶漢式是指在使用時才進行例項化。如下 餓漢式 public class singleton publ...

設計模式單例模式之double check

設計模式之雙重判定鎖 double check 下面列出乙個比較常用的也是我個人最喜歡的一種在多執行緒的情況下,又能滿足lazy loading,效率又高的一種單例模式的寫法 class singleton 在這可能有些小夥伴會問這個volatile這個是幹啥的,給出答案 volatile這個關鍵字...