什么是單例設計模式?
單例模式,是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中,應用該模式的類一個類只有一個實例。即一個類只有一個對象實例。
類結構圖
具體實現
需要:
(1)將構造方法私有化,使其不能在類的外部通過new關鍵字實例化該類對象。
(2)在該類內部產生一個唯一的實例化對象,並且將其封裝為private static類型。
(3)定義一個靜態方法返回這個唯一對象。
實現一:立即加載 / “餓漢模式”
立即加載就是使用類的時候已經將對象創建完畢(不管以后會不會使用到該實例化對象,先創建了再說。很着急的樣子,故又被稱為“餓漢模式”),常見的實現辦法就是直接new實例化。
public class Singleton { // 將自身實例化對象設置為一個屬性,並用static、final修飾 private static final Singleton instance = new Singleton(); // 構造方法私有化 private Singleton() {} // 靜態方法返回該實例 public static Singleton getInstance() { return instance; } }
“餓漢模式”的優缺點:
優點:實現起來簡單,沒有多線程同步問題。
缺點:當類SingletonTest被加載的時候,會初始化static的instance,靜態變量被創建並分配內存空間,從這以后,這個static的instance對象便一直占着這段內存(即便你還沒有用到這個實例),當類被卸載時,靜態變量被摧毀,並釋放所占有的內存,因此在某些特定條件下會耗費內存。
實現二:延遲加載 / “懶漢模式”
延遲加載就是調用get()方法時實例才被創建(先不急着實例化出對象,等要用的時候才給你創建出來。不着急,故又稱為“懶漢模式”),常見的實現方法就是在get方法中進行new實例化。
public class Singleton { // 將自身實例化對象設置為一個屬性,並用static修飾 private static Singleton instance; // 構造方法私有化 private Singleton() {} // 靜態方法返回該實例 public static Singleton getInstance() { if(instance == null) { instance = new Singleton(); } return instance; } }
“懶漢模式”的優缺點:
優點:實現起來比較簡單,當類SingletonTest被加載的時候,靜態變量static的instance未被創建並分配內存空間,當getInstance方法第一次被調用時,初始化instance變量,並分配內存,因此在某些特定條件下會節約了內存。
缺點:在多線程環境中,這種實現方法是完全錯誤的,根本不能保證單例的狀態。
實現三:線程安全的“懶漢模式”
public class Singleton { // 將自身實例化對象設置為一個屬性,並用static修飾 private static Singleton instance; // 構造方法私有化 private Singleton() {} // 靜態方法返回該實例,加synchronized關鍵字實現同步 public static synchronized Singleton getInstance() { if(instance == null) { instance = new Singleton(); } return instance; } }
優點:在多線程情形下,保證了“懶漢模式”的線程安全。
缺點:眾所周知在多線程情形下,synchronized方法通常效率低,顯然這不是最佳的實現方案。
實現四:DCL雙檢查鎖機制(DCL:double checked locking)
public class Singleton { // 將自身實例化對象設置為一個屬性,並用static修飾 private static Singleton instance; // 構造方法私有化 private Singleton() {} // 靜態方法返回該實例 public static Singleton getInstance() { // 第一次檢查instance是否被實例化出來,如果沒有進入if塊 if(instance == null) { synchronized (Singleton.class) { // 某個線程取得了類鎖,實例化對象前第二次檢查instance是否已經被實例化出來,如果沒有,才最終實例出對象 if (instance == null) { instance = new Singleton(); } } } return instance; } }
方法四算是單例模式的最佳實現方式。內存占用率高,效率高,線程安全,多線程操作原子性。
參考
1、高洪岩,Java多線程編程核心技術,機械工業出版社
2、https://www.cnblogs.com/yinxiaoqiexuxing/p/5605338.html