單利模式的兩種最佳實現

我妻禮彌發表於2018-06-11

在23種設計模式中單利模式算是比較簡單的一種設計模式了,雖然簡單,但是他的實現卻有很多種。下面會給出兩種最佳實現和其他一些常見的實現方式。

單元素列舉

不需要延遲載入時的最佳實現

public enum Singleton {

    //每個元素就是一個單例
    INSTANCE;

    //業務方法
    public void method(){}
}
複製程式碼

優點:

  • 能防止反射
  • 能防序列化
  • 執行緒安全
  • 呼叫效率高

缺點:

  • 不能延時載入

靜態內部類

需要延遲載入時的最佳實現

public class Singleton {

    //1. 建立私有的 靜態內部類
    private static class inner {
        //1.1 在靜態內部類裡,建立 私有的 靜態的 外部類物件
        private static Singleton instance = new Singleton();
    }

    //2. 私有化構造器,禁止他人建立例項
    private Singleton() {
    }

    //3. 建立 公開的 靜態的 獲取例項的方法
    public static  Singleton getInstance() {
        return inner.instance;
    }
}
複製程式碼

優點:

  • 執行緒安全
  • 呼叫效率高
  • 能延時載入

缺點:

  • 不能能防止反射
  • 不能防序列化

餓漢式

public class Singleton  {
    //1. 建立私有的 靜態的內部例項
    private static Singleton instance = new Singleton();

    //2. 私有化構造器,禁止他人建立例項
    private  Singleton(){}

    //3. 建立 公開的 靜態的 獲取例項的方法
    public static Singleton getInstance(){
        return instance;
    }
}
複製程式碼

優點:

  • 執行緒安全
  • 呼叫效率高

缺點:

  • 不能能防止反射
  • 不能防序列化
  • 不能延時載入

懶漢式

public class Singleton {
    //1. 建立私有的 靜態的內部例項,並初始化為null
    private static  Singleton instance  = null;

    //2. 私有化構造器,禁止他人建立例項
    private Singleton() {
    }

    //3. 建立 公開的 靜態的 獲取例項的方法
    public static  Singleton getInstance() {
        // 先判斷單例是否為空,以避免重複建立
        if( instance == null){
            instance = new Singleton();
        }
        return instance;
    }
}
複製程式碼

優點:

  • 能延時載入 缺點:
  • 不能能防止反射
  • 不能防序列化
  • 執行緒不安全
  • 呼叫效率不高

懶漢式 + 同步鎖

public class Singleton {
    //1. 建立私有的 靜態的內部例項,並初始化為null
    private static  Singleton instance  = null;

    //2. 私有化構造器,禁止他人建立例項
    private Singleton() {
    }

    //3. 建立 公開的 靜態的 獲取例項的方法
    public static synchronized Singleton getInstance() {
        // 加入同步鎖
        if (instance == null)
            instance = new Singleton();
        return instance;
    }
}
複製程式碼

優點:

  • 能延時載入
  • 執行緒安全 缺點:
  • 不能能防止反射
  • 不能防序列化
  • 呼叫效率不高

雙重校驗鎖(懶漢式的改進)

注意:JVM的指令重排序,可能會導致雙重校驗鎖失效

public class Singleton {
    //1. 建立私有的 靜態的內部例項,並初始化為null
    private static  Singleton instance  = null;

    //2. 私有化構造器,禁止他人建立例項
    private Singleton() {
    }

    //3. 建立 公開的 靜態的 獲取例項的方法
    public static  Singleton getInstance() {
        // 加入雙重校驗鎖
        // 校驗鎖1:第1個if
        if( instance == null){
            synchronized (Singleton.class){
                // 校驗鎖2:第2個 if
                if( instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
複製程式碼

優點:

  • 能延時載入
  • 執行緒安全 缺點:
  • 不能能防止反射
  • 不能防序列化
  • 呼叫效率不高

雙重校驗鎖優化(規避指令重排序的影響)

使用 volatile 關鍵字來防止指令重排序

public class Singleton {
    //1. 建立私有的 靜態的 可見的 內部例項,並初始化為null
    private static volatile Singleton instance  = null;

    //2. 私有化構造器,禁止他人建立例項
    private Singleton() {
    }

    //3. 建立 公開的 靜態的 獲取例項的方法
    public static  Singleton getInstance() {
        // 加入雙重校驗鎖
        // 校驗鎖1:第1個if
        if( instance == null){
            synchronized (Singleton.class){
                // 校驗鎖2:第2個 if
                if( instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
複製程式碼

優點:

  • 能延時載入
  • 執行緒安全 缺點:
  • 不能能防止反射
  • 不能防序列化
  • 呼叫效率不高

相關文章