設計模式之單例模式

2021-10-05 11:18:54 字數 3078 閱讀 3950

定義:保證乙個類只有乙個例項,並且提供乙個全域性訪問點

場景:執行緒池,資料庫連線池等

實現方式:

1.懶漢模式:

只有使用的時候,才初始化。延遲載入

//使用的時候才初始化

//jvm 乙個例項

public class lazysingleton

public static lazysingleton getinstance()

} return instance;

}}

給變數加volatile是為了防止cpu指令重排,我們來看下方的demo例子:

public class demo 

}

0: new	         #1    	// class demo            1.分配空間,返回乙個指向該空間的記憶體引用

3: dup

4: invokespecial #16 // method "":()v 2.對空間進行初始化

7: astore_1 // 3.把記憶體引用賦值給demo變數

「4:」和「7:」這兩個指令順序可能會顛倒(reordering),也就是先把記憶體引用賦值給demo變數,然後對空間進行初始化。這時候就出現問題了,我們看lazysingleton這個類:如果記憶體引用賦值給instance變數後,還沒有進行初始化,這時候另外乙個執行緒進入"getinstance()"方法,他會發現這個instance已經被賦值了,就會直接執行「return instance」來返回例項,但是這個例項還沒有被初始化,這就可能會導致空指標等異常。所以,我們要在變數前加volatile修飾來防止cpu重排。

總結:

(1).保證執行緒安全

(2).防止指令重排

(3).雙重檢查,優化加鎖過程

2.餓漢模式:

在類載入階段就完成了例項的初始化,通過類載入機制保證執行緒安全

類載入過程:

(1).類載入:載入對應的二進位制檔案,在方法區建立對應的資料結構 (載入class檔案到方法區,在方法區建立相應類物件)

(2).連線:a.驗證(確保class檔案的正確性)  b.準備(為靜態變數分配記憶體和設定初始值)  c.解析(符號引用替換為直接引用)

(3).初始化:給靜態屬性賦值

public class hungrysingleton 

private hungrysingleton() {}

}

3.靜態內部類:

public class innerclasssingleton 

public static innerclasssingleton getinstance()

private innerclasssingleton()

}}

在外界呼叫"getinstance()" 的時候,內部類innerclass才會被類載入器載入,然後在載入過程中初始化instance。為了防止遭到反射攻擊,可以在私有構造器中加入初始化判斷,如果instance已被初始化,就說明單例類遭到破壞,此時可以向外界丟擲異常

4.列舉型別:

public enum enumsingleton
反射機制不允許例項化列舉型別,原始碼如下:

if ((clazz.getmodifiers() & modifier.enum) != 0)

throw new illegalargumentexception("cannot reflectively create enum objects");

列舉型別也可以防止反序列化攻擊,原始碼如下:

string name = readstring(false);

enum<?> result = null;

class<?> cl = desc.forclass();

if (cl != null) catch (illegalargumentexception ex)

if (!unshared)

}

當使用反序列化獲取列舉物件時,會通過"valueof()"方法來根據名字(name)查詢列舉物件。

5.序列化:

public class serializablesingleton implements serializable

private serializablesingleton()

//反序列化時,從此方法中拿取例項

object readresolve() throws objectstreamexception

}

serialversionuid:如果我們沒有設定這條屬性,系統會預設的幫我們隨機分配乙個uid,這時候我們將這個類序列化到磁碟上。然後當我們修改這個類中的內容的時候,系統又會隨機再分配乙個uid。此時修改後的類和磁碟上的類因為uid不同,所以互相不相容。即:serializablesingleton instance != (serializablesingleton)object

readresolve():在反序列化時獲得的物件和通過"getinstance()"方法獲得的物件不是同乙個物件,為了解決這個問題,我們寫乙個特殊方法:"readresolve()",有了這個方法,在反序列化過程中,就會從這個方法中獲得該類的例項。

我們用objectoutputstream和objectinputstream來寫出和讀入:

private static void useserializablesingleton() throws exception

設計模式之單例模式

前一段時間買了一本秦小波寫的 設計模式之禪 網上對這書的評價很高。現在還沒有看很多,但是有些地方頗有感觸,也並不是所有的地方都能看懂,但是會慢慢研究的。自己對於設計模式的感覺就是乙個字 牛!感覺會23種設計模式並且會熟練運用的人,真的就是大師級的牛人了,設計模式是乙個專案主管或者架構師一定要會的東西...

設計模式之單例模式

package com.xie.singleton public class singleton 提供乙個共有的靜態的入口方法 public static singleton getinstance 懶漢式 延遲載入 提供乙個私有的靜態的成員變數,但不做初始化 private static sing...

設計模式之 單例模式

單例模式 singleton 保證乙個類僅有乙個例項,並提供乙個訪問它的全域性訪問點。單例模式 單件模式 使用方法返回唯一的例項 public class singleton private static singleton instance public static singleton geti...