1. 程式人生 > 其它 >設計模式 最基礎也最重要的單例模式

設計模式 最基礎也最重要的單例模式

設計模式 最基礎也最重要的單例模式

餓漢式單例

顧名思義 很餓很著急 會在程式執行一開始就吧類物件加載出來
所以有著可能浪費資源的缺點
簡單例子:

//餓漢式單例
public class Hungry {
    //可能會導致空間的浪費
    private byte[] data=new byte[1024*1024];
    //核心思想 構造器私有化
    private Hungry(){

    }

    private final static Hungry HUNGRY=new Hungry();

    public static Hungry getInstance(){
        return HUNGRY;
    }
}

懶漢式單例

懶漢式單例的思想是 當需要用到我時才建立物件 但是簡單的寫法會在多執行緒出現問題

//懶漢式單例
public class LazyMan {
    private LazyMan(){
        System.out.println(Thread.currentThread().getName()+"執行了建立方法");
    }

    private static LazyMan lazyMan;

    public static LazyMan getInstance(){
        if(lazyMan == null) {
            lazyMan = new LazyMan();
        }
        return lazyMan;
    }

    public static void main(String[] args) {
        for(int i=0;i<10;i++){
            new Thread(()->{LazyMan.getInstance();}).start();
        }
    }
}

執行結果可能會隨機出現多個執行緒建立了物件 不符合單例模式的思想

雙重鎖實現多執行緒懶漢實現

//懶漢式單例
public class LazyMan {
    private LazyMan(){
        System.out.println(Thread.currentThread().getName()+"執行了建立方法");
    }

    private static LazyMan lazyMan;

    public static LazyMan getInstance(){
        //外層判斷主要是優化 使得不是每次都要獲取鎖
        //雙重鎖懶漢式 稱為DCL懶漢
        if(lazyMan==null){
            synchronized (LazyMan.class){
                if(lazyMan == null) {
                    lazyMan = new LazyMan();
                }
            }
        }
        return lazyMan;
    }

    public static void main(String[] args) {
        for(int i=0;i<10;i++){
            new Thread(()->{LazyMan.getInstance();}).start();
        }
    }
}

通過鎖就可以實現只能一個執行緒獲取物件
但是實際上這樣在極端情況下也不是安全的 原因在與語句
lazyMan = new LazyMan(); 底層是執行了很多步驟的 同時並不是原子操作
有可能出現第一個執行緒在建立物件 還沒完全建立完畢時 第二個執行緒判斷已經建立完畢 最後返回空物件
解決方法:
新增volatile關鍵字
private volatile static LazyMan lazyMan;