懶漢式單例設計詳解

2021-10-06 10:01:10 字數 3479 閱讀 9849

public

class

lazytype

public

static lazytype getinstance()

return lazytype;

}}

測試類

public

class

testlazyton

}

輸出結果:

看似正常,實則在多執行緒情況下會出現問題

在構造方法中加入一行列印輸出**

在測試類中建立多執行緒來呼叫getinstance()方法

public

class

testlazyton).

start()

;}}}

輸出結果

證明以上設計在多執行緒環境下不安全。

雙重檢測鎖可以解決以上問題。

public

class

lazytype

public

static lazytype getinstance()

}}return lazytype;

}}

此時再執行main方法便只會建立乙個物件,但在極端情況下還是會出問題。在執行lazytype的構造方法時,由於其不是乙個原子性操作,會分為一下三步:

1.在記憶體中給即將要建立的物件分配記憶體空間(記憶體位址)

2.建立物件

3.讓第2步建立的物件執行第1步的記憶體位址。

但由於程式在執行的過程中可能會發生指令重排,也就是可能會按照2,1,3或者1,3,2的步驟去建立物件,假設a執行緒已分配記憶體空間,且指向了記憶體位址,但還沒有例項物件,也就是1,3,2的步驟,那麼此時b執行緒進入getinstance()方法在判斷lazytype == null時發現lazytype不為null,但此時並沒有真正建立物件,所以b執行緒可能產生異常。為了避免此現象,則要使用volatile關鍵字修飾lazytype避免問題。

public

class

lazytype

public

static lazytype getinstance()

}}return lazytype;

}}

以上方式在用反射的方式獲取物件時依然是有問題的。

public

class

testlazyton

).start();

// }

constructor

declaredconstructor = lazytype.

class

.getdeclaredconstructor

(null)

; declaredconstructor.

setaccessible

(true);

// 雖然構造方法私有,但只要將該方法通過反射設定為可訪問的就可以例項物件

lazytype lazytype = declaredconstructor.

newinstance()

; lazytype lazytype1 = declaredconstructor.

newinstance()

; system.out.

println

(lazytype)

; system.out.

println

(lazytype1);}

}

輸出結果

這樣即便是雙重檢測在使用反射的情況下也是有問題的。

可以通過乙個全域性變數和在構造器中丟擲異常的方式來解決以上問題。

public

class

lazytype

else

}public

static lazytype getinstance()

}}return lazytype;

}}

此時在執行測試程式,則只會執行一次構造方法,在執行第二次的時候丟擲了異常。

但是如果將flag屬性通過反射設定為accessible以後,以上操作依然是不安全的。

public

class

testlazyton

).start();

// }

constructor

declaredconstructor = lazytype.

class

.getdeclaredconstructor

(null)

; declaredconstructor.

setaccessible

(true);

// 雖然構造方法私有,但只要將該方法通過反射設定為可訪問的就可以例項物件

lazytype lazytype = declaredconstructor.

newinstance()

;//在執行完第一次構造方法以後,獲取flag屬性並設定訪問許可權

field flag = lazytype.

class

.getdeclaredfield

("flag");

flag.

setaccessible

(true);

//然後將flag屬性的值從true在置為false

flag.

set(lazytype,

false);

lazytype lazytype1 = declaredconstructor.

newinstance()

; system.out.

println

(lazytype)

; system.out.

println

(lazytype1);}

}

輸出結果:

可以發現構造方法又執行了兩次。

懶漢式單例設計模式

懶漢式單例設計模式 特點 什麼時候用,什麼時候開闢空間.缺點 多執行緒模式下,會出現問題,達不到單例模式的效果 步驟 1.構造方法私有化 2.定義乙個私有的.靜態的.類的成員變數,但不為其賦初始值 設定初始值為null 3.提供乙個名稱為getinstance 的公共的.靜態的方法,在方法中先判斷步...

單例設計模式(懶漢式)

版本 v1.0 public class study 6 10 物件是方法被呼叫時,才初始化,也叫做物件的延時載入。稱為 懶漢式 single類進記憶體,物件還沒有存在,只有呼叫了getinstance方法時,才建立物件 開發一般用餓漢式 如果乙個人呼叫方法沒有問題,如果多個人一起呼叫就會出問題,就...

單例(懶漢式單例 餓漢式單例)

public class singleton private static singleton instance new singleton public static singleton getinstance public class singleton public static synchr...