單例模式基礎概念
單例模式是一種創建型設計模式,其核心思想是確保一個類僅有一個實例,并提供一個全局訪問點來獲取這個實例。在 Java 中實現單例模式主要有以下關鍵點:
- 私有構造函數?- 防止外部通過
new
關鍵字創建實例 - 靜態實例變量?- 類內部持有唯一實例的引用
- 靜態訪問方法?- 提供全局訪問該實例的入口
單例模式的幾種實現方式
1. 餓漢式(線程安全)
餓漢式是最簡單的實現方式,在類加載時就創建實例:
public class EagerSingleton {// 類加載時就初始化實例private static final EagerSingleton instance = new EagerSingleton();// 私有構造函數private EagerSingleton() {}// 靜態訪問方法public static EagerSingleton getInstance() {return instance;}
}
優點:實現簡單,線程安全
缺點:類加載時就創建實例,可能造成資源浪費
2. 懶漢式(非線程安全)
懶漢式在首次調用時才創建實例,但存在線程安全問題:
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}// 非線程安全的獲取實例方法public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}
優點:延遲加載,避免資源浪費
缺點:多線程環境下可能創建多個實例
3. 懶漢式(線程安全,同步方法)
為了解決線程安全問題,可以對獲取實例的方法進行同步:
public class LazySingletonSynchronized {private static LazySingletonSynchronized instance;private LazySingletonSynchronized() {}// 同步方法,保證線程安全public static synchronized LazySingletonSynchronized getInstance() {if (instance == null) {instance = new LazySingletonSynchronized();}return instance;}
}
優點:線程安全,延遲加載
缺點:同步方法開銷大,影響性能
4. 雙重檢查鎖定(Double-Checked Locking)
結合懶加載和性能優化的雙重檢查鎖定實現:
public class DoubleCheckedLockingSingleton {// 使用volatile關鍵字保證可見性和禁止指令重排序private static volatile DoubleCheckedLockingSingleton instance;private DoubleCheckedLockingSingleton() {}public static DoubleCheckedLockingSingleton getInstance() {// 第一次檢查,避免不必要的同步if (instance == null) {synchronized (DoubleCheckedLockingSingleton.class) {// 第二次檢查,確保在同步塊內沒有其他線程創建實例if (instance == null) {instance = new DoubleCheckedLockingSingleton();}}}return instance;}
}
優點:線程安全,延遲加載,性能優化
缺點:實現復雜,需要理解 volatile 關鍵字的作用
5. 靜態內部類(推薦)
利用 Java 靜態內部類的特性實現高效、線程安全的單例:
public class StaticInnerClassSingleton {private StaticInnerClassSingleton() {}// 靜態內部類,持有外部類的實例private static class SingletonHolder {private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();}public static StaticInnerClassSingleton getInstance() {return SingletonHolder.INSTANCE;}
}
優點:線程安全,延遲加載,實現簡單
缺點:無法傳遞參數
6. 枚舉(最佳實踐)
使用枚舉實現單例是最簡潔、最安全的方式:
public enum EnumSingleton {INSTANCE;// 可以添加實例方法public void doSomething() {System.out.println("Singleton method called");}
}
優點:
- 線程安全
- 防止反序列化重新創建新的對象
- 防止反射攻擊
- 實現簡單
缺點:無法實現延遲加載
單例模式的應用場景
單例模式在以下場景中經常使用:
- 資源管理器?- 如數據庫連接池、文件系統
- 配置信息類?- 全局配置信息的讀取和管理
- 日志記錄器?- 統一的日志輸出管理
- GUI 組件?- 如窗口管理器、對話框等
注意事項
- 序列化問題:如果單例類實現了 Serializable 接口,需要添加 readResolve () 方法防止反序列化創建新實例
- 反射攻擊:私有構造函數可以被反射破壞,枚舉實現可以避免此問題
- 多線程環境:必須考慮線程安全問題,推薦使用靜態內部類或枚舉實現
單例模式雖然簡單,但在實際應用中需要根據具體場景選擇合適的實現方式,同時注意處理好各種邊界情況,確保單例的唯一性和安全性。