設計模式:1.單例模式

什麼是單例模式

單例模式目的是保證在程序運行期間一個類只有一個實例,並提供一個全局訪問點,無論什麼情況下,只會生成一個實例,免去繁瑣的創建銷燬對象的過程。

如何設計單例

如何設計單例模式其實很簡單,只需要考慮一個問題,實例是否可以保證是全局唯一,只要滿足這個條件,這個單例設計的肯定就合格了。

其中懶漢模式,餓漢模式,雙重檢查方式實現,靜態內部類的實現方式都可以概括爲以下兩步:

構造函數私有化,保證在外部無法new對象
提供一個static方法獲取當前實例(不同方案,實現不同)
當然枚舉的實現方式最簡單,也最安全的,所以推薦使用枚舉實現,其次推薦使用靜態內部類方式實現。

餓漢模式
不是延遲加載,加載類的時候直接初始化

/**
 * @auther: linan
 * @date: 2020/5/25 16:26
 * @description:
 */
public class Singleton {

    private static Singleton singleton = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance(){
        return singleton;
    }
}

優點:線程安全,代碼簡單。

缺點:不是延遲加載,如果你用不到這個類,它也會實例化,還有一個問題就是如果這個實例依賴外部一些配置文件,參數什麼的,在實例化之前就要獲取到,否則就實例化異常

懶漢模式
延遲加載,首次需要使用的時候在實例化,需要考慮線程安全

線程不安全的實現方式

public class Singleton {

    private static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getInstance(){
        if(null == singleton){
            singleton = new Singleton();
        }
        return singleton;
    }
}

雙重檢查(DCL:Double Check Lock)
線程安全的實現方式:

public class Singleton {

    private static volatile Singleton singleton;

    private Singleton() {
    }

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

爲什麼使用volatile修飾singleton變量?

說的volatile,首先肯定回答volatile的可見性
防止重排序優化,如果不用volatile修飾,多線程的情況下,可能會出現線程A進入synchronized代碼塊,執行new Singleton();,首先給singleton分配內存,但是還沒有初始化變量,這時候線程B進入getInstance方法,進行第一個判斷,此時singleton已經不爲空,直接返回singleton,然後肯定報錯。使用volatile修飾之後禁止jvm重排序優化,所以就不會出現上面的問題

靜態內部類實現
使用靜態內部類實現也是延遲加載,利用靜態內部類去實現線程安全,只有在第一次調用getInstance方法的時候纔會去加載SingletonHolder,初始化SINGLETON

public class Singleton {

    private Singleton() {
    }

    public static Singleton getInstance(){
        return SingletonHolder.SINGLETON;
    }

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

枚舉實現
枚舉實現代碼更簡潔,線程安全,並且保證枚舉不會被反序列化,反射和克隆

/**
 * @auther:linan
 * @date: 2020/5/25 16:30
 * @description:
 */
public enum Singleton {
    
    SINGLETON;

    /**
     * 提供的方法
     */
    public void method(){
        System.out.println("枚舉實現");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章