單例模式:5種實現方式

微信搜索:碼農StayUp
主頁地址:https://gozhuyinglong.github.io
源碼分享:https://github.com/gozhuyinglong/blog-demosjava

1. 單例模式

單例模式(Singleton Pattern)是一種簡單的對象建立型模式。該模式保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。git

因此要實現單例模式,要作到如下幾點:github

  • 將構造方法私有化,杜絕使用構造器建立實例。
  • 須要自身建立惟一的一個實例,並提供一個全局訪問入口

2. 單例模式的幾種實現

對於單例模式有如下5種實現。安全

2.1. 懶漢式

該方式是使用synchronized關鍵字進行加鎖,保證了線程安全性。
優勢:在第一次調用才初始化,避免了內存浪費。
缺點:對獲取實例方法加鎖,大大下降了併發效率。微信

因爲加了鎖,對性能影響較大,不推薦使用。多線程

public class SingletonLazy {

    /**
     * 私有實例
     */
    private static SingletonLazy instance;

    /**
     * 私有構造方法
     */
    private SingletonLazy() {
    }

    /**
     * 惟一公開獲取實例的方法(靜態工廠方法),該方法使用synchronized加鎖,來保證線程安全性
     *
     * @return
     */
    public static synchronized SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }

}

2.2 餓漢式

餓漢式是利用類加載機制來避免了多線程的同步問題,因此是線程安全的。
優勢:未加鎖,執行效率高。
缺點:類加載時就初始化實例,形成內存浪費。併發

若是對內存要求不高的狀況,仍是比較推薦使用這種方式。性能

public class SingletonEager {

    /**
     * 私有實例,靜態變量會在類加載的時候初始化,是線程安全的
     */
    private static final SingletonEager instance = new SingletonEager();

    /**
     * 私有構造方法
     */
    private SingletonEager() {
    }

    /**
     * 惟一公開獲取實例的方法(靜態工廠方法)
     *
     * @return
     */
    public static SingletonEager getInstance() {
        return instance;
    }
}

2.3 雙重校驗鎖

利用了volatile修飾符的線程可見性(被一個線程修改後,其餘線程當即可見),即保證了懶加載,又保證了高性能,因此推薦使用。編碼

public class SingletonDCL {

    /**
     * 私有實例,volatile修飾的變量是具備可見性的(即被一個線程修改後,其餘線程當即可見)
     */
    private volatile static SingletonDCL instance;

    /**
     * 私有構造方法
     */
    private SingletonDCL() {
    }

    /**
     * 惟一公開獲取實例的方法(靜態工廠方法)
     *
     * @return
     */
    public static SingletonDCL getInstance() {
        if (instance == null) {
            synchronized (SingletonDCL.class) {
                if (instance == null) {
                    instance = new SingletonDCL();
                }
            }
        }
        return instance;
    }
}

2.4 靜態內部類

該模式利用了靜態內部類延遲初始化的特性,來達到與雙重校驗鎖方式同樣的功能。因爲須要藉助輔助類,並不經常使用。線程

public class SingletonInnerClass {

    /**
     * 私有構造方法
     */
    private SingletonInnerClass() {
    }

    /**
     * 惟一公開獲取實例的方法(靜態工廠方法)
     *
     * @return
     */
    public static SingletonInnerClass getInstance() {
        return LazyHolder.INSTANCE;
    }

    /**
     * 私有靜態內部類
     */
    private static class LazyHolder {
        private static final SingletonInnerClass INSTANCE = new SingletonInnerClass();
    }
}

2.5 枚舉類

該方式利用了枚舉類的特性,不只能避免線程同步問題,還防止反序列化從新建立新的對象。這種方式是 Effective Java 做者 Josh Bloch 提倡的方式。

但因爲這種編碼方式還不能適應,因此實際工做中不多使用。

public enum SingletonEnum {

    INSTANCE;

    public void method() {
        System.out.println("枚舉類中定義方法!");
    }

}

推薦閱讀

相關文章
相關標籤/搜索