設計模式總結 —— 單例設計模式

大棋發表於2019-04-20

一、定義

      確保某一個類只有一個例項,而且自行例項化並向整個系統提供這個例項。

二。使用場景

      當物件需要消耗的資源過多(如訪問Io、資料庫等),避免產生多個物件消耗過多的資源,或者某種型別的物件只應該有且只有一個。

三、實現方法

(1)餓漢單例模式

      依靠靜態物件的初始化實現單例

public class Singleton{
    private static Singleton mInstance = new Singleton();
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance(){
        return mInstance;
    }
}
複製程式碼

(2)懶漢單例模式

      第一次呼叫getInstance()後,單例物件就會被例項化。但每次呼叫getInstance()方法時都需要進行同步,會造成不必要的消耗。
      對於不頻繁呼叫getInstance()的情況下,可以適用。

public class Singleton{
    private static Singleton mInstance;
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance(){
        if( mInstance == null){
            mInstance = new Singleton();
        }
        return mInstance;
    }
}
複製程式碼

(3) Double Check Lock(DCL) 實現單例

public class Singleton{
    private volatile static Singleton mInstance;
    
    private Singleton() {}
    
    public static Singleton getInstance(){
        if( mInstance == null){
            synchronized(Singleton.class){
                if( mInstance == null){
                    mInstance = new Singleton();
                }
            }
        }
        return mInstance;
    }
}
複製程式碼

      進行兩次判空,第一次判斷主要避免不必要的同步,第二次判斷主要為了在同步情況下確認單例仍為空時,進行初始化。

volatile關鍵字的作用:
      1、防止重排序
      new物件時,會進行三件事件:
            (1)、給Singleton的例項分配記憶體;
            (2)、呼叫Singleton()的構造方法,初始化成員變數。
            (3)、將mInstance物件指向分配的記憶體空間。
而在JVM中(2)和(3)的順序是無法被保證的,只能通過volalite保證其有序性。

      2、保證執行緒的可見性。

(4) 靜態內部類單例模型

依靠靜態內部類被使用時才被JVM載入的原理。

public class Singleton{
    private Singleton{}
    public static Singleton getInstance(){
        return SingletonHolder.mInstance;
    }
    
    //靜態內部類
    private static class SingletonHolder{
        private static final Singleton mInstance = new Singleton();
    }
}
複製程式碼

靜態內部類和非靜態內部類載入時機的區別:

      非靜態內部類,一定需要外部類例項化後才會被載入。

      靜態內部類的載入不需要依附外部類,在使用時才載入進。

(5) 使用容器實現單例。

將多種單例型別注入到一個統一的管理類中,使用時根據key獲取對應的單例物件。

public class SingletonManager{
    private static Map<String,Object> objMap = new HashMap<String,Object>();
    private SingletonManager{}
    
    public static void registerService(String key,Object instance){
        if(!object.containsKey(key)){
            objMap.put(key,instance);
        }
    }
    
    public static Object getService(String key){
        return objMap.get(key);
    }
}
複製程式碼

(6) 列舉單例

列舉型別可以定義自己的方法和自己的變數,而且列舉例項的建立是執行緒安全的,並且任何情況下都是單例。

public enum SingletonEnum{
    INSTANCE;
    public void doSomething(){
        System.out.println("do ");
    }
}
複製程式碼

相關文章