一、單例模式的概念
單例模式是一種創建型模式,它保證一個類只能被實例化一次,並提供了一個訪問該實例的全局訪問點。單例模式可以用來解決資源統一分配的問題,如線程池、全局緩存等。
單例模式的標準實現包含三個要素:1.私有的構造函數,2.靜態變數實例,3.公共的訪問方法。而實現單例模式的方式有很多,接下來我們將討論這些實現方式。
二、單例模式的五種實現方式
下面是單例模式的五種實現方式:
餓漢式
public class Singleton { 一個私有的、靜態的、final類型的實例對象 private static final Singleton INSTANCE = new Singleton(); 私有構造函數 private Singleton() {} 公開訪問點 public static Singleton getInstance() { return INSTANCE; } }
餓漢式單例模式在類載入時已經創建了實例對象,因此不存在線程安全問題,但是如果實例對象很大,會導致啟動時間變長。
懶漢式
public class Singleton { 私有的實例對象 private static Singleton instance = null; 私有構造函數 private Singleton() {} 公開訪問點 public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
懶漢式單例模式在第一次調用公開訪問點時才創建實例對象,解決了餓漢式單例模式啟動時間長的問題。但是在多線程環境下,存在線程安全問題,需要加鎖。
雙重檢查
public class Singleton { 一個私有的、volatile類型的實例對象 private static volatile Singleton instance = null; 私有構造函數 private Singleton() {} 公開訪問點 public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
雙重檢查單例模式在多線程環境下解決了線程安全問題,並且不需要每次都加鎖,相對於懶漢式單例模式有更優的性能。
靜態內部類
public class Singleton { 私有構造函數 private Singleton() {} 私有靜態內部類 private static class SingletonHolder { 一個私有的、靜態的、final類型的實例對象 private static final Singleton INSTANCE = new Singleton(); } 公開訪問點 public static Singleton getInstance() { return SingletonHolder.INSTANCE; } }
靜態內部類單例模式在外部類被載入的時候並不會被初始化,只有在調用公開訪問點時才會初始化內部類,從而創建實例對象。這種方式既避免了餓漢式單例模式的啟動時間長的問題,又避免了懶漢式單例模式的線程安全問題。
枚舉
public enum Singleton { INSTANCE; 公開方法 public void doSomething() {} }
枚舉單例模式是餓漢式單例模式的升級版,它天生就是線程安全的,並且可以防止反序列化創建新的實例對象。其優點在於簡潔明了,不需要做額外的工作即可實現單例模式。
三、單例模式的幾種實現方式
除了上述五種實現方式之外,還有一些單例模式的實現方式:
延遲初始化佔位類
public class Singleton { 私有變數 private String data = "this is a lazy initialized singleton"; 私有構造函數 private Singleton() {} 私有靜態內部類 private static class Holder { 私有靜態變數 private static final Singleton INSTANCE = new Singleton(); } 私有靜態初始化方法 private static final Singleton getInstance() { return Holder.INSTANCE; } 公開訪問點 public String getData() { return data; } }
延遲初始化佔位模式是一種比較新穎的單例實現方式,它通過聲明一個私有的靜態內部類,該內部類包含單例的實例對象,並在第一次調用公開訪問點時才初始化該實例對象,從而達到懶漢式單例模式的效果,並且不需要加鎖保證線程安全。
ThreadLocal
public class Singleton { 一個私有的ThreadLocal類型的實例對象 private static ThreadLocal instance = new ThreadLocal() {{ initialValue = new Singleton(); }}; 私有構造函數 private Singleton() {} 公開訪問點 public static Singleton getInstance() { return instance.get(); } }
ThreadLocal單例模式是一種較為特殊的單例實現方式,它結合了懶漢式單例模式和多線程環境下線程安全的特性,並且在每個線程中都可以有自己獨立的實例對象,從而達到可重入的效果。
四、單例模式的6種實現方式
除了上述介紹的五種實現方式之外,還有一種單例模式的實現方式,來看看它的實現:
註冊式單例
public class Singleton { 一個私有的靜態Map類型的實例對象 private static Map registry = new ConcurrentHashMap(); 靜態代碼塊 static { Singleton instance = new Singleton(); registry.put(instance.getClass().getName(), instance); } protected Singleton() {} 公共靜態方法,返回指定名稱的單例對象 public static Singleton getInstance(String name) { if (name == null) { name = Singleton.class.getName(); } if (registry.get(name) == null) { registry.put(name, new Singleton()); } return registry.get(name); } }
註冊式單例模式將每個實例對象都註冊到一個Map容器中,以便在需要時快速獲取。該實現方式相對於其他實現方式來說比較複雜,而且需要考慮線程安全問題。
五、7種方式實現單例模式
雖然單例模式的標準實現方式只有三個要素,但是在實際使用的時候,我們還可以按照以下的七種方式來實現單例模式:
枚舉
和上面的枚舉單例模式一樣,這裡就不再重複介紹了。
餓漢式
和上面的餓漢式單例模式一樣,這裡就不再重複介紹了。
懶漢式
和上面的懶漢式單例模式一樣,這裡就不再重複介紹了。
雙重檢查
和上面的雙重檢查單例模式一樣,這裡就不再重複介紹了。
靜態內部類
和上面的靜態內部類單例模式一樣,這裡就不再重複介紹了。
延遲初始化佔位類
和上面的延遲初始化佔位類單例模式一樣,這裡就不再重複介紹了。
ThreadLocal
和上面的ThreadLocal單例模式一樣,這裡就不再重複介紹了。
六、實現單例模式的類具有
實現單例模式的類具有以下特點:
1.只能被實例化一次;
2.提供一個訪問該實例的全局訪問點;
3.在多線程環境下保證線程安全;
4.防止反序列化時創建新的實例對象。
七、單例模式的實現
以上方式都是通過私有的構造函數、靜態變數以及公開訪問點來實現單例模式的。
八、單例模式代碼實現
下面是一個簡單的單例模式實現的示例代碼:
public class Singleton { 一個私有的、靜態的、final類型的實例對象 private static final Singleton INSTANCE = new Singleton(); 私有構造函數 private Singleton() {} 公開訪問點 public static Singleton getInstance() { return INSTANCE; } }
九、總結
單例模式是一種重要的設計模式,它可以幫助我們解決資源統一分配的問題,並且提升了程序的可維護性和可測試性。在實際開發中,我們可以選擇適合自己的單例模式實現方式,並注意線程安全問題。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/240810.html