設計模式:單例模式

簡單來說,單例模式指在應用的整個生命週期中,只存在一個實例對象。由此可知,單例模式可用於那些整個應用中只存在一個對象的場景,如配置文件、線程池、緩存、例子對象、工具類等。如果創造出多個對象,會出現很多問題,如佔用過多資源、不一致的結果等。

UML類圖

根據是否lazy初始化,可將單例模式分爲“餓漢”和“懶漢”式實現。

“餓漢”式實現

“餓漢”式實現 會在整個應用啓動初始化時,就會創建一個實例對象。“餓漢”式實現 是線程安全的,但是由於在應用啓動時創建,所以會使得應用啓動時間變長。

常規實現

public class Singleton {

    // 靜態變量,聲明並初始化
    private static Singleton instance = new Singleton();

    // 私有化構造方法
    private Singleton() {
    }

    // 對外提供示例獲取的靜態方法
    public static Singleton getInstance() {
        return instance;
    }

}

實現簡單,線程安全。

枚舉實現

public enum Singleton {

    INSTANCE;

    public void method_name() {

    }

    ...

}

這種方式是絕對線程安全的,並支持自動序列化機制。

“懶漢”式實現

“懶漢”式實現 在應用啓動時不會立即創建一個實例對象,是在首次被請求調用獲取實例對象的方法時才創建對應的實例對象,所以應用啓動過程相對“餓漢”式實現會快一點。

簡單實現

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;

    // 私有化構造方法
    private Singleton() {
    }

    // 對外提供示例獲取的靜態方法,使用Synchronized加鎖
    public static Synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }

}

多線程情況下,線程安全,但加鎖 synchronized影響效率。

雙重鎖實現

雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking),實現示例如下:

public class Singleton {

    // 靜態變量,僅聲明;volatile保證及時可見性
    private volatile static Singleton instance;

    // 私有化構造方法
    private Singleton() {
    }

    // 對外提供示例獲取的靜態方法
    public static Singleton getInstance() {
        if(instance == null) {
            // 檢測到未創建時,才加鎖保證創建過程是互斥和同步的
            Synchronized(Singleton.class) {
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

}

線程安全;雙重鎖校驗,可保證多線程下的高性能。

靜態內部類實現

public class Singleton {

    private static class SingletonHolder {

        private static final Singleton INSTANCE = new Singleton();

    }

    // 私有化構造方法
    private Singleton() {
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }

}

線程安全;這種實現使用了classloader機制,達到的效果和雙重鎖實現差不多。

總結

一般情況下,不建議使用 簡單實現 和 常規實現 方式,建議使用“餓漢”式實現。只有在要明確實現 lazy loading 效果時,使用靜態內部類的方式更佳。如果涉及到反序列化創建對象時,可以嘗試使用枚舉實現方式。如果有其他特殊的需求,可以考慮使用雙重鎖校驗方式。

發佈了52 篇原創文章 · 獲贊 105 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章