前言
單例模式(Singleton Pattern)是一種創建型設計模式,確保一個類僅有一個實例,并提供全局訪問點。它在需要控制資源(如數據庫連接、配置管理)或避免重復創建對象的場景中廣泛應用。
一,核心概念與特點
- 唯一性確保在整個應用程序生命周期中,一個類只有一個實例存在。
- 全局訪問點通過靜態方法(如getInstance())提供唯一實例的訪問入口。
- 延遲加載部分實現在首次調用時才創建實例,節省資源。
二, 實現方式及代碼示例
1.餓漢式單例模式(Eager Initialization)
特點:類加載時立即初始化實例,線程安全但可能浪費資源。
public class Singleton {private static final Singleton INSTANCE = new Singleton();private Singleton() {} // 私有構造器public static Singleton getInstance() { return INSTANCE; }
}
private static final Singleton INSTANCE = new Singleton();定義了一個私有的,靜態的,不可改變的Singleton類實例(單例模式中類唯一生成的對象INSTANCE)。在類加載時立即初始化實例,靜態意味著這個實例屬于類本身,而不是類的某個具體對象。私有確保了這個實例只能在類內部訪問。這意味著這個實例一旦初始化后就不能被改變。
private Singleton() {}是一個私有的構造方法也是單例模式的核心,防止類的外部通過new關鍵字來創建SingleTon類的實例,使得外部無法直接實例化這個類。
public static Singleton getInstance() { return INSTANCE; }這個靜態方法是用來獲取SingleTon類的唯一實例(INSTANCE),也就是全局唯一訪問節點。靜態方法可通過類名直接調用
該餓漢式單例??適合資源占用小、高頻率訪問且無需延遲加載的場景??。雖然存在內存浪費風險,但其簡潔性、線程安全性和執行效率使其在多數場景中仍是可靠選擇。
2.懶漢式單例模式(Lazy Initialization)
特點:線程不安全,??多線程下可能創建多個實例。
public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) { instance = new Singleton(); }return instance;}
}
private static Singleton instance;私有靜態變量,用于持有類的唯一實例。instance屬于類本身,而不是類的某個實例。與餓漢模式不同,實例創建時間被推遲。
private Singleton() {};私有構造方法,防止外部通過new創建類的實例。
public static Singleton getInstance(){};用于獲取類的唯一實例。如果實例為空,則創建SingleTon實例;否則,返回已存在的實例。
線程不安全:若線程A和線程B同時調用getInstance()切均檢測到instance==null,會各自執行new SingleTon(),生成兩個不同的實例,破壞單例唯一性。
即使實例已經被創建,其他線程可能因為緩存未刷新,仍讀到null。
為此進行優化。
3.雙重檢查鎖(Double-Checked Locking)?
特點;減少同步次數,僅首次創建時加鎖,需用volatile禁止指令重排序.
public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) { instance = new Singleton(); }}}return instance;}
}
private static volatile DCLSingleton instance;volatile確保多線程環境下的可見性:當一個線程更新了 instance 變量后,其他線程會立即看到更新后的值。和有序性:禁止指令重排序,new Singleton()的步驟(分配內存--->初始化對象--->賦值引用)可能被重新排序(分配內存--->賦值引用--->初始化對象)若未初始化完成時其他線程訪問instance,會得到未完全構造的對象。volatile會確保對象完全初始化后才暴露引用。
在唯一訪問節點getInstance方法中中采用雙重null檢索機制,第一次檢查,如果instance為null,才進入同步塊。synchronized (Singleton.class)對DCLSingleton()進行同步,確保同一時刻只有一個線程可以執行該代碼塊,防止多個線程突破第一次檢查后重復創建實例。第二次檢查在進入同步塊后,instance仍然為null,才創建實例。
這種單例模式常用于高并發下需要懶加載(類加載時沒有立即初始化實例)的單例且要求線程安全的場景,例如數據庫連接池,配置管理等。
總結
餓漢式單例啟動立即開始初始化,占用內存但是訪問速度快,以空間換時間;懶漢式單例延遲加載,省內存,以時間換空間。
餓漢式適用于實例輕量,高并發頻繁訪問(如工具類)。
懶漢式適用于重量級實例,需懶加載。