單例模式的一些認識

private AAA(){
}

1 餓漢式 (線程安全,不能延遲實例化,浪費內存空間)

private static AAA aaa = new AAA();
public static AAA getInstance(){
    return aaa;
}

2 懶漢式 (線程安全,延遲實例化)

private static AAA instance;
public static synchronized AAA getInstance(){

    if(instance==null){
        instance = new AAA();
    }
    return instance;
}

3 Double Check Lock(雙重鎖機制,線程安全,延遲實例化,效率高)

private static volatile AAA instance;
public static AAA getInstance(){

    if(instance == null){
        synchronized (AAA.class){
            if (instance ==null){
                instance = new AAA();
            }
        }
    }
    return instance;
}

關於此方式中的volatile作用

(1)禁止指令重排序

主要是因爲

instance = new AAA();不是一個原子操作

下面這個鏈接清楚的解釋了指令重排序的問題。

https://www.jianshu.com/p/1c72a061b40e

(2)保證可見性

線程A在自己工作線程中創建了實例,但還未同步到主存中,線程B判斷主存中instance還是null,那麼線程B又將在自己工作線程中創建一個實例,這樣就會創建多個實例。

 

4 靜態內部類(線程安全,延遲實例化,效率高)

private static class BBB{
    private static final AAA aaa = new AAA();
}

public static AAA getInstance(){
    return BBB.aaa;
}

靜態內部類的加載方式:

內部靜態類不會自動初始化,只有調用靜態內部類的方法,靜態域,或者構造方法的時候纔會加載靜態內部類。

 

5、枚舉(線程安全,調用效率高,不能延時加載,可以天然的防止反射和反序列化調用)

舉個栗子:一旦你實現了serializable接口,他們就不再是單例的了,因爲readObject()方法總是返回一個 新的實例對象,就像java中的構造器一樣。

public enum BBC {

    //枚舉元素本身就是單例
    INSTANCE;
    
    private BBC() {
    
    }
    
    //添加自己需要的操作
    public void singletonOperation(){
    }
}
    /**
      * 使用方法
      */
    boolean bl = BBC.INSTANCE.singletonOperation();

枚舉完成的單例有一下幾個優點: 
1,線程安全 
2,自由序列化 
3,即使使用反射機制也無法多次實例化一個枚舉量

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章