1. 程式人生 > 實用技巧 >CSDN部落格徹底去廣告,自動展開,去彈窗 2020.10.20 親測有效

CSDN部落格徹底去廣告,自動展開,去彈窗 2020.10.20 親測有效

date: 2020-09-28 16:09:00
updated: 2020-09-28 17:42:00

單例模式

1. 餓漢式

public class EHan {
    private static EHan instance = new EHan();
    private EHan(){}
    public static EHan getInstance(){
        return instance;
    }
}

優點:沒有執行緒安全問題
缺點:在初始化時就建立好了,浪費記憶體空間

2. 懶漢式

2.1 執行緒不安全

public class LHan {
    private static LHan instance;
    private LHan(){}
    public static LHan getInstance(){
        if(instance == null){
            instance = new LHan();
        }
        return instance;
    }
}

優點:只有當用的時候才檢查是否有例項,沒有才建立
缺點:有執行緒安全與不安全兩種,區別在於是否有 synchronized 關鍵字

2.2 執行緒安全

public class LHan {
    private static LHan instance;
    private LHan(){}
    public static synchronized LHan getInstance(){
        if(instance == null){
            instance = new LHan();
        }
        return instance;
    }
}

3. DCL

由於執行緒安全的懶漢式的 synchronized 是加在方法上的,如果該方法裡還有其他的一些程式碼,會降低執行效率,加鎖的粒度太粗,所以可以進而改寫下面這個

3.1 懶漢式優化後的一種寫法

public class LHan {
    private static LHan instance;
    private LHan(){}
    public static LHan getInstance(){
        if(instance == null){
            synchronized(this){
                instance = new LHan();
            }
        }
        return instance;
    }
}

但是這種寫法也存在一定問題,當執行緒A在判斷instancenull後停住了,此時還沒有建立例項;執行緒B搶到了資源,發現instancenull,也會進入到程式碼塊,於是A和B都會建立一個例項。

3.2 DCL 單例模式

Double Check Lock 兩次檢查,中間插入一個lock

public class LHan {
    private static volatile LHan instance; // 必須要加 volatile
    private LHan(){}
    public static LHan getInstance(){
        if(instance == null){ // 這一層判斷是為了提高效率。鎖競爭很耗費時間和效率,避免多個執行緒每一次getInstance都要進入到同步程式碼塊
            synchronized(this){
                if(instance == null){
                    instance = new LHan();
                }
            }
        }
        return instance;
    }
}

有可能會存在,A在第一層判斷結束後停住,B進入同步程式碼塊,new一個物件例項,進行一定操作後,把instance置為null,然後A進入同步程式碼塊,會再次new一個物件。解決:新增版本號。

4. 靜態內部類

public class Singleton {
    private static class SingletionHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton(){}
    public static final Singleton getInstance(){
        return SingletionHolder.INSTANCE;
    }

}

靜態內部類的方式效果類似雙檢鎖,但實現更簡單。但這種方式只適用於靜態域的情況,雙檢鎖方式可在例項域需要延遲初始化時使用。