首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Android 單例模式全解析:七種實現方式與最佳實踐

     編輯:Java 相關知識

單例模式核心意圖

確保一個類只有一個實例,並提供全域訪問點

解決問題:降低耦合、節省資源、統一狀態管理(如倉庫管理、配置中心、資料庫連接池)。

經典場景:倉庫管理

工人搬貨進出倉庫,若每個工人持有不同倉庫實例,會導致庫存數據不一致。單例確保全系統只有一個 StoreHouse 實例。

七種實現方式詳細對比

1. 餓漢式——最簡單、線程安全

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() { return INSTANCE; }
}
  • 類載入時即建立實例(JVM 保證線程安全)
  • 適用:實例建立快、記憶體佔用小、啟動即需使用
  • 缺點:無法延遲載入,可能浪費記憶體

2. 懶漢式——延遲載入,但非線程安全

public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) instance = new Singleton();
        return instance;
    }
}
  • 首次調用才建立
  • 多線程下可能建立多個實例

3. 同步鎖修正懶漢式——線程安全但效能差

public static synchronized Singleton getInstance() {
    if (instance == null) instance = new Singleton();
    return instance;
}
  • 整個方法加鎖,並發效能低

4. 雙重檢查鎖 (DCL)——推薦的懶漢式寫法

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 禁止指令重排,保證實例發布完整性
  • 首次建立加鎖,後續無鎖讀取,效能優

5. 靜態內部類——完美結合延遲載入與線程安全

public class Singleton {
    private Singleton() {}
    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}
  • 外部類載入時不初始化內部類
  • 首次調用 getInstance() 觸發內部類初始化,JVM 保證線程安全
  • 代碼簡潔,強烈推薦

6. 枚舉單例——《Effective Java》作者 Josh Bloch 推薦

public enum Singleton {
    INSTANCE;
    public void doSomething() { ... }
}

// 使用
Singleton.INSTANCE.doSomething();
  • 天然線程安全、防序列化破壞、防反射攻擊
  • 最簡潔、最強健,**首選方案**

7. 容器管理(Spring / Dagger / Hilt)

現代 Android 開發多交由依賴注入框架管理單例生命週期:

// Spring
@Singleton
@Component
public class MyService { ... }

// Dagger/Hilt
@Singleton
@Provides
MyService provideMyService() { return new MyService(); }

單例模式優缺點

優點缺點
受控的唯一訪問點職責過重,違反單一職責原則
節省記憶體(避免頻繁創建/銷毀)長期持有可能阻礙 GC,導致記憶體洩漏
可擴展為多例、線程局部單例單元測試困難(全域狀態難隔離)
全域狀態共享便利隱式依賴,降低代碼可讀性

Android 實戰注意事項

  1. Application 生命週期:單例持有 Context 必須用 ApplicationContext,否則洩漏 Activity
  2. 多進程:Android 多進程下每個進程有獨立 JVM,**單例不跨進程**
  3. 序列化/反序列化:實作 readResolve() 返回同一實例
  4. 反射攻擊:枚舉天然免疫,其他方式需在建構子檢查 if (INSTANCE != null) throw ...

總結建議

場景推薦方式
一般工具類、管理器枚舉單例 / 靜態內部類
需延遲初始化、建立耗時靜態內部類 / DCL
Android 框架整合Hilt/Dagger @Singleton
需防序列化/反射破壞枚舉單例
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved