1. 程式人生 > >設計模式之單例模式(創建型)

設計模式之單例模式(創建型)

HR 創建型 業務 ... 多次調用 () get 很好 餓漢

前言

本博客介紹一種創建型模式:單例模式
這是一種比較容易理解的設計模式,可以理解為創建對象的一種很好的做法。可以盡量避免創建過多的對象,給JVM造成很大的負載。

應用場景

單例模式的一些應用場景:
1、比如數據連接類,這是需要經常調用的
2、網站訪問量統計的服務類,需要多次調用
3、導出導入Excel表,一些業務復雜的系統需要多次調用
...

總結起來就是需要經常調用的通用類,我們可以用單例模式進行很好的設計。

編程思想

單例模式涉及了兩種重要的編程思想:懶加載思想和緩存思想

緩存思想:

    private static Singleton instance = null;//先放內存緩存
   
    public static Singleton getInstance() {
        if (instance == null) {//內存加載不到,創建對象
            instance = new Singleton();
        }
        return instance;//內存緩存有,直接調用
    }

懶加載思想:
下面例子就是懶加載的簡單應用,創建一個對象都是需要用的時候實例,盡量不要在加載類的時候就實例了,這種方法可以很好的避免給JVM增加負載。這是一種很好的編程習慣。

public static Singleton getInstance() {
        if (instance == null) {//對象需要用時才實例
            instance = new Singleton();
        }
        return instance;
    }

單例模式實例

下面介紹幾種常用的單例模式實例

1、懶漢模式
這是一種線程不安全,懶加載的方式

public class Singleton {
    private static Singleton instance;
    //定義private構造函數,使類不可以被實例
    private Singleton (){}

    /**
     * 懶漢模式,線程不安全,懶加載
     * @return
     */
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

上面例子線程不安全,要線程安全可以加個同步鎖,不過加了同步鎖性能又不好了,加載慢

public class Singleton {
    private static Singleton instance;
    //定義private構造函數,使類不可以被實例
    private Singleton (){}

    /**
     * 懶漢模式,線程安全,懶加載
     * @return
     */
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

2、餓漢模式
下面介紹一下單例模式的另外一種實現方式,餓漢模式
其實現原理就是在類內部全局new一個對象,利用Java虛擬機的類加載機制,保證了線程安全,不過很明顯,一創建了,就實例了單例類,會給JVM增加負載

public class Singleton {
    //定義private構造函數,使類不可以被實例
    private Singleton (){}


    //加載類的時候,利用JVM的類加載機制創建對象,保證了線程安全,但是效率不好
    private static Singleton instance = new Singleton();

    /**
     * 餓漢模式,線程安全,非懶加載
     * @return
     */
    public static Singleton getInstance() {
        return instance;
    }
}

3、雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)
下面介紹一種雙檢鎖的實現方式,這種方式看起來稍稍比較復雜了點,不過可以實現線程安全,同時雙檢鎖的方式可以保證性能比較高

public class Singleton {
 
    //定義private構造函數,使類不可以被實例
    private Singleton (){}

    private volatile static Singleton instance;

    /**
     * 雙檢鎖/雙重校驗鎖(DCL,即 double-checked locking)線程安全,懶加載
     * @return
     */
    public static Singleton getInstance(){
        if(instance == null){
            synchronized (Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

4、登記式/內部類
下面用內部類的方式來實現單例模式,這種方式可以和餓漢模式來對比一下
這種方式和剛才介紹的餓漢模式類似,不過區別就是做到了懶加載,我們可以分析例子。方法就是在單例類裏加個內部類,這樣做就不會像餓漢模式一樣,單例類一加載就實例對象。當調用getInstance方法的時候,才會調用,創建對象。這樣就做到了懶加載,同時也是利用JVM保證了線程安全

public class Singleton {
   
    //定義private構造函數,使類不可以被實例
    private Singleton (){}

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

    /**
     * 登記式/靜態內部類,線程安全,懶加載
     * @return
     */
    public static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

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

/**
     * 枚舉方式
     */
    public enum Singleton {
        INSTANCE;
        public void whateverMethod() {
        }
    }

設計模式之單例模式(創建型)