你會幾種單例模式的寫法?

概要

單例模式常常會是咱們學習設計模式的第一個模式。在spring框架下,Bean的默認初始化也是單例模式。 單例模式常見的有懶漢模式和餓漢模式。 先來講說這兩個命名由來。 懶漢模式: lazily 餓漢模式: early 感受是音譯。。。java

用途

通常狀況下,單例對象應該是無狀態的,也就是說沒有成員變量字段,或者說成員變量不發生變化。 而有狀態的對象,每每在系統中是多例存在。不一樣的實例擁有不一樣的狀態。spring

實現方式

餓漢模式

public class Singleton{
    private final static Singleton INSTANCE = new Singleton();
    private Singleton(){}
    public static getInstance(){
        return INSTANCE;
    }
}
複製代碼

優勢: 線程安全,實現簡單,容易理解。 缺點: 空間浪費。在啓動的時候就會建立實例。設計模式

餓漢模式&代碼塊

public class Singleton {
    private static Singleton INSTANCE;
    static {
        INSTANCE = new Singleton();
    }
    private Singleton(){}

    public static Singleton getInstance() {
        return INSTANCE;
    }
}
複製代碼

這種方式和第一種沒有區別。安全

懶漢模式

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(){}

    public static synchronized Singleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}
複製代碼

要解決線程安全問題,最簡單的作法是讓方法加個同步。這樣一來即可保證線程安全,可是帶來的問題是性能損耗。由於其實只有在第一次構造的時候須要同步,之後獲取的時候不須要同步的。框架

懶漢模式&double check

public class Singleton {
    private static Singleton INSTANCE;
    private Singleton(){}

    public static Singleton getInstance() {
        if (INSTANCE != null) {
            return INSTANCE;
        }
        synchronized (Singleton.class) {
            if (INSTANCE == null) {
                INSTANCE = new Singleton();
            }   
        }
        return INSTANCE;
    }
}
複製代碼

這種方式就比較完美了。作一個雙重檢查,保證了在第一次構造實例的時候的線程安全。同時也保證了以後獲取實例對象不須要同步。性能

懶漢模式&內部類

public class Singleton {
    private static class SingletonInstance {
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton(){}

    public static Singleton getInstance() {
        return SingletonInstance.INSTANCE;
    }
}
複製代碼

這種方式表面上看和餓漢模式很類似,可是其實也是實現了懶加載。巧妙之處在於利用了內部類啓動機制保證了線程安全。我的比較推薦以上兩種寫法。學習

枚舉用法

public enum Singleton {
    INSTANCE;
}
複製代碼

坊間還有使用枚舉類來實現的例子,雖然也能達到單例的效果,同時也是線程安全。可是我的並不推崇這種用法,緣由在於枚舉並非設計來實現單例的,理解起來會讓人困惑。spa

相關文章
相關標籤/搜索