單例模式的各種實現

帥的雅痞啊發表於2020-12-18

單例模式

模式動機

對於系統中的某些類來說,只有一個例項很重要,如一個系統中只有一個計時工具和ID(序號)生成器。

單例模式適用情況包括:系統只需要一個例項物件;客戶呼叫類的單個例項只允許使用一個公共訪問點。

定義

顧名思義,用來保證一個物件只能建立一個例項,除此之外,它還提供了對例項的全域性訪問方法。

單例模式的要點有三個:一是某個類只能有一個例項;二是它必須自行建立這個例項;三是它必須自行向整個系統提供這個例項。

實現

為了確保單例例項的唯一性,所有的單例構造器都要被宣告為私有的,在通過宣告靜態方法實現全域性訪問獲得該單例例項。

懶漢式

public class Singleton {
  private static Singleton instance;
  private Singleton(){}

  public static Singleton getInstance(){
    if(instance == null)
      instance = new Singleton();
    return instance;
  }
}

餓漢式

public class Singleton {
  private static Singleton instance = new Singleton();
  private Singleton(){}

  public static Singleton getInstance(){
    return instance;
  }
}

雙重校驗鎖

public class Singleton {
  private volatile static Singleton instance = new Singleton();
  private Singleton(){}

  public  static Singleton getInstance(){
    if(instance == null)
      synchronized (Singleton.class){
        if(instance == null)
          instance = new Singleton();
      }
    return instance;
  }
}

注意: volatile 修飾是必須的, instance = new Singleton()可以拆解為3步
1、分配記憶體
2、初始化物件
3、指向分配的地址,若發生重排序
假設A 執行緒執行了1 和 3,還沒有執行2,B執行緒來判斷是否為NULL,B執行緒 就會直接返回還沒初始化的instance,volatile可以避免重排序。

/**
 * 無鎖的執行緒安全單例模式
 */
public class Singleton {
  private static final Singleton instance = new Singleton();
  private Singleton(){}
  public static synchronized Singleton getInstance(){
    return instance;
  }
}

靜態內部類
通過靜態內部類的方式實現單例模式是執行緒安全的,同時靜態內部類不會在Singleton類載入時就載入,而是在呼叫getInstance()方法時才進行載入,達到了懶載入的效果。可能還存在反射攻擊或者反序列化攻擊

public class Singleton {
    private static class SingletonHolder {
        private static Singleton instance = new Singleton();
    }
    private Singleton() {
        
    }
    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

列舉實現

public enum Singleton {
    INSTANCE;
    public void doSomething() {
        System.out.println("doSomething");
    }
}

相關文章