確保一個類只有一個實例,並提供全域訪問點
解決問題:降低耦合、節省資源、統一狀態管理(如倉庫管理、配置中心、資料庫連接池)。
工人搬貨進出倉庫,若每個工人持有不同倉庫實例,會導致庫存數據不一致。單例確保全系統只有一個 StoreHouse 實例。
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() { return INSTANCE; }
}
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) instance = new Singleton();
return instance;
}
}
public static synchronized Singleton getInstance() {
if (instance == null) instance = new Singleton();
return instance;
}
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;
}
}
volatile 禁止指令重排,保證實例發布完整性public class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
getInstance() 觸發內部類初始化,JVM 保證線程安全public enum Singleton {
INSTANCE;
public void doSomething() { ... }
}
// 使用
Singleton.INSTANCE.doSomething();
現代 Android 開發多交由依賴注入框架管理單例生命週期:
// Spring
@Singleton
@Component
public class MyService { ... }
// Dagger/Hilt
@Singleton
@Provides
MyService provideMyService() { return new MyService(); }
| 優點 | 缺點 |
|---|---|
| 受控的唯一訪問點 | 職責過重,違反單一職責原則 |
| 節省記憶體(避免頻繁創建/銷毀) | 長期持有可能阻礙 GC,導致記憶體洩漏 |
| 可擴展為多例、線程局部單例 | 單元測試困難(全域狀態難隔離) |
| 全域狀態共享便利 | 隱式依賴,降低代碼可讀性 |
Context 必須用 ApplicationContext,否則洩漏 ActivityreadResolve() 返回同一實例if (INSTANCE != null) throw ...| 場景 | 推薦方式 |
|---|---|
| 一般工具類、管理器 | 枚舉單例 / 靜態內部類 |
| 需延遲初始化、建立耗時 | 靜態內部類 / DCL |
| Android 框架整合 | Hilt/Dagger @Singleton |
| 需防序列化/反射破壞 | 枚舉單例 |