單例實現備忘

1. 常見方式

保證線程安全條件下有三種方式:

  • 提前初始化:類加載時就創建一個對象,

  • 延遲初始化

    • DCL:雙重檢查,JDK5.0後單例實例加volatile修飾

    • 佔位類:推遲佔位類的初始化

提前初始化可能影響程序啓動時間以及不必要高開銷操作較少採用

2. DCL

public class DoubleCheckLocking {
    private static Resource resource;
    public static Resource getInstance(){
        if(resource == null){
            synchronized (DoubleCheckLocking.class){
                if (resource == null){
                    resource = new Resource()
                }
            }
        }
        return resource
    }
}

上述代碼的問題在於在沒有同步的情況下讀取一個共享對象,可能發生的情況是獲取一個沒有完成初始化的對象,部分屬性是失效的。

在缺少Happens-Before關係時,可能出現指令重排序。初始化對象如果需要寫入多個變量,發佈對象引用也需要寫入一個變量。上述無法保證發佈引用在另一個線程加載該引用前,新對象引用的寫操作與屬性的寫操作會重排,這樣新線程會看到引用的最新值,但是部分屬性失效。

JDK5.0後爲resource家volatile修飾可以使用DCL,但是這種方法已經被廣泛廢棄,佔位模式更容易理解

3. 佔位類

public class DoubleCheckLocking {
    private static class ResourceHolder{
        public static Resource resource = new Resource();
    }
    
    public static Resource getInstance(){
        return ResourceHolder.resource;
    }
}


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