1. 常見方式
java
保證線程安全條件下有三種方式:安全
提早初始化:類加載時就建立一個對象,app
延遲初始化
ide
DCL:雙重檢查,JDK5.0後單例實例加volatile修飾線程
佔位類:推遲佔位類的初始化對象
提早初始化可能影響程序啓動時間以及沒必要要高開銷操做較少採用
排序
2. DCLget
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關係時,可能出現指令重排序。初始化對象若是須要寫入多個變量,發佈對象引用也須要寫入一個變量。上述沒法保證發佈引用在另外一個線程加載該引用前,新對象引用的寫操做與屬性的寫操做會重排,這樣新線程會看到引用的最新值,可是部分屬性失效。it
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; } }