一、單例模式的概念
單例模式是一種創建型模式,它保證一個類只能被實例化一次,並提供了一個訪問該實例的全局訪問點。單例模式可以用來解決資源統一分配的問題,如線程池、全局緩存等。
單例模式的標準實現包含三個要素: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-hk/n/240810.html
微信掃一掃
支付寶掃一掃