單例模式詳解

只能生成一個實例的類是實現了Singleton(單例)模式的類型。實現單例模式的程式碼比較短,在面試中經常被提及,這篇隨筆介紹幾種常見的實現方式。

1.餓漢模式

這種實現方式優點是沒有加鎖,執行效率高、執行緒安全的;但是對象在類載入的時候就會被創建,容易產生垃圾對象,正常情況下使用這種方式來創建單例。具體程式碼如下:

public class Singleton {
    // 構造方法私有化 
    private Singleton(){}
    // 類載入就創建實例
    private static Singleton instance = new Singleton();
    // 對外提供獲取實例的方法
    public static Singleton getInstance() {  
        return instance;  
    }  
}

2.懶漢模式

最基本的實現方式,執行緒不安全。

public class Singleton {
    // 構造方法私有化 
    private Singleton(){}
    // 靜態實例
    private static Singleton instance; 
    // 對外提供獲取實例的方法,需要的時候再創建實例
    public static Singleton getInstance() {  
        if (instance == null) {
           instance = new Singleton();
        }
        return instance;  
    }  

3.懶漢模式,執行緒安全

這種模式在 getInstance()方法上加了同步鎖,當一個執行緒獲取鎖來創建實例,那麼其他執行緒只能等待鎖被釋放。其中一個執行緒拿到鎖後發現實例已經被創建了,就使用已經創建好的實例,效率較低。兩種懶漢模式都不推薦使用。

public class Singleton {
    // 構造方法私有化 
    private Singleton(){}
    // 靜態實例
    private static Singleton instance; 
    // 對外提供獲取實例的方法,需要的時候再創建實例
    public static synchronized Singleton getInstance() {  
        if (instance == null) {
           instance = new Singleton();
        }
        return instance;  
    }  
}

4.雙重校驗鎖(double-checked locking, DCL)

在實例創建之前我們需要對方法加鎖,那麼創建以後就無需重複加鎖操作,盡最大可能提高程式的執行效率。對上面的程式碼進行改進,這種方式適用於有特殊需求的場景:

public class Singleton {
    // 構造方法私有化 
    private Singleton(){}
    // 靜態實例
    private static Singleton instance; 
    public static Singleton getInstance() {  
        if (instance == null) {
            // 對Singleton類加鎖
           synchronized(Singleton.calss) {
               if (instance == null) {
                   instance = new Singleton();
               }
           }
        }
        return instance;  
    }  
}

5.靜態內部類

這種方法會在Singleton類內部再創建一個靜態內部類,只有顯示調用 getInstance()時,實例才會被創建。這種方式適用於靜態域需要延遲初始化的場景。

public class Singleton {
     private Singleton (){} 
     private static class SingletonHolder {
         // final修飾,無法再指向其他對象
         private static final Singleton INSTANCE = new Singleton();
     }
    // 鎖定方法,防止子類繼承重寫方法 
     public static final Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

 

參考資料:《Head First 設計模式》

     《劍指offer》第二版