設計模式 - 單例模式(Singleton Pattern)

常見單例實現方式:

1.懶漢式

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

線程安全但每次調用都加鎖導致效率低

2.餓漢式

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

使用靜態變量實現唯一性
但類裝載時就創建實例,雖然導致類裝載的原因有很多種,在單例模式中大多數都是調用 getInstance 方法
但是也不能確定有其他的方式(或者其他的靜態方法)導致類裝載
這時候初始化 instance 顯然沒有達到 lazy loading 的效果。

3.雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)

public class Singleton {
    private volatile static Singleton singleton;
    private Singleton (){}
    public static Singleton getSingleton() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

將同步鎖置於第一個判空之內,所以只有第一次實例化時對效率有影響
之所以需要第二個判空,是因爲進入第一個判空之後,同步鎖之前,有可能切換到另一個線程,這時候另一個線程的第一個判空依然是通過的,如果沒有第二個判空,便可能產生2個實例.

4.登記式/靜態內部類

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

這是對餓漢式的改進,使用靜態內部類來實現懶加載

5.枚舉

public enum Singleton {
    INSTANCE;
    public void whateverMethod() {
    }
}

使用Singleton.INSTANCE調用實例
這種方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不僅能避免多線程同步問題,而且還自動支持序列化機制,防止反序列化重新創建新的對象,絕對防止多次實例化。
不過,由於 JDK1.5 之後才加入 enum 特性,用這種方式寫不免讓人感覺生疏,在實際工作中,也很少用。

總結

一般情況下,不建議使用懶漢式,建議使用餓漢式,畢竟裝載了單例類卻不調用單例方法的並不常見。
如果涉及到反序列化創建對象時,可以嘗試使用枚舉方式。
如果有其他特殊的需求,可以考慮使用雙檢鎖方式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章