單例模式:5種實現方式


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

1. 單例模式

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

所以要實現單例模式,要做到以下幾點:

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

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("枚舉類中定義方法!");
    }

}

推薦閱讀


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM