GOF23之單例模式

2021-09-25 16:19:50 字數 3164 閱讀 4113

單例模式是gof23中最簡單的模式。單例的設計模式裡的出場率很高,它簡單但也有多種實現方式,也正是因為它的靈活性和重要性使喚其多次出現在面試筆試中,經常與工廠模式搭配使用。

作用

保證乙個類只能有乙個例項。多次建立只會返回同乙個例項。

作用範圍

如word中的工具箱,任何時候只能有乙個工具箱。(大話設計模式)

window的任務管理器等等

實現步驟

私有化類的所有構造方法,使呼叫者不可直接通過new建立該類例項

單例類中暴露乙個名為getinstance()的靜態方法來為呼叫者返回乙個例項物件

1. 餓漢式
/**

* 單例模式之餓漢式

*/public class singleton1 ;

//在類初始化時就建立類的例項

private static singleton1 singleton = new singleton1();

//對外暴露的方法獲取單例物件

public static singleton1 getinstance()

}

優點:獲取例項效率高

缺點:如果存在初始化類後並沒有獲取使用單例物件這種情況就會造成記憶體的浪費。

2. 懶漢式
/**

* 單例模式之懶漢式

*/public class singleton2 ;

//此處並不初始化單例物件

private static singleton2 singleton= null;

//對外暴露的方法獲取單例物件

public synchronized static singleton2 getinstance()

return singleton;

}}

特點:在類初始化時不建立例項,在呼叫者第一次呼叫getinstance方法時才建立例項。

優點:比起餓漢式避免了記憶體的浪費,執行緒安全

缺點:為避免多執行緒環境下建立出多個單例物件,採用同步機制,導致懶漢式多執行緒環境下的效率低下。

多執行緒破壞單例的情況為:多個執行緒一同呼叫getinstance方法(且均為第一次呼叫),並一同以singleton==null進入了if語句塊,執行緒1進入同步**塊,執行緒2在外等待執行緒1執行結束。此時單例物件已經存在,待執行緒1建立物件後出來,執行緒2會繼續建立物件,破壞了單例模式。

3. 靜態內部類

/**

* 單例模式之靜態內部類

*/public class singleton3

public static singleton3 getinstance()

}

優點

效率高執行緒安全

類初始化時並不初始化其內部類,只有在呼叫getinstance方法時才會初始化內部類,實現懶載入。

4. 列舉
/**

* 單例模式之靜態內部類

*/public enum singleton4

優點:天然執行緒安全,由jvm底層保障。並且避免反射反序列化破解單例的漏洞。

缺點:無延時載入。

5. 雙重鎖定
/**

* 單例模式之雙重鎖

* */

public class singleton5 ;

//在類初始化時並不建立例項

private static volatile singleton5 singleton = null;

//對外暴露的方法獲取單例物件

public static singleton5 getinstance()

}} return singleton;

}}

特點:因為雙重鎖定使用先判斷後進同步**塊的方式,比起餓漢式效率高了一點,先判斷單例物件是否為null,為null才進入同步。

在jdk1.5前因沒有引入volatile關鍵字,singleton = new singleton5()此行**會分解出如下三行偽**。

1 memory=allocate();// 分配記憶體 相當於c的malloc

2 ctorinstanc(memory) //初始化物件

3 instance=memory //設定instance指向剛分配的位址

偽**的排序順序有可能是1-2-3,也有可能是1-3-2。在多執行緒環境下假設執行緒a的執行順序為1-3-2,在執行完3**後被掛起,執行緒b來判斷instance不為null會直接返回,出現instance沒有初始化的情況,會導致程式出錯。故jdk1.5前不推薦使用。

注:除列舉式外所有的單例模式都會被反射和反序列化所破解為多個例項物件。在此給出防止破解的方法

反射:

/**

* 反射破解單例模式

*/public class test

}

解決方案:在構造方法中加入如下語句,在反射第二次通過呼叫構造方法建立例項時,singleton!=null,這時就手動丟擲異常來阻止單例物件的建立。

private singleton5()

};

2.反序列化:

/**

* 反序列化破解單例模式

*/public class test catch (ioexception e) catch (classnotfoundexception e)

}}

此時輸出結果s1與s3不為同乙個物件。解決辦法就是在單例類中新增乙個方法

private object readresolve()
在物件的反序列化時會呼叫此方法,直接返回singleton物件就可防止這次現象發生。

單例模式的幾種實現並沒有優劣,只有在適應的場景選擇適合的實現。

在需要懶載入的情況 靜態內部類 優於 懶漢式

不需要懶載入記憶體充裕 列舉式 優於 餓漢式

設計模式GOF23之單例模式

單例模式的五種方式 主要 懶漢式,餓漢式 其他 雙重檢測鎖 double checking模式 靜態內部類,列舉模式 選取時機 延時載入,占用內部資源大 靜態內部類好於懶漢 不延時載入,占用內部資源小 列舉好於餓漢 單例模式 懶漢式 author 小帆敲 public class demo01 上鎖...

設計模式GOF23之單例模式

單例模式的五種方式 主要 懶漢式,餓漢式 其他 雙重檢測鎖 double checking模式 靜態內部類,列舉模式 選取時機 延時載入,占用內部資源大 靜態內部類好於懶漢 不延時載入,占用內部資源小 列舉好於餓漢 單例模式 懶漢式 author 小帆敲 public class demo01 上鎖...

GoF23 單例(Singleton)模式

目標之一 提高程式的可復用性 有哪些功能可以被擴充套件?擴充套件功能時必須修改哪些地方?有哪些類不需要修改?保證在jvm中只有乙個例項。需要該物件時,new例項物件。不安全 class singleton 當需要時才例項化,之後都是乙個例項。懶漢式不安全,所以需要加上同步。return public...