Double Check Lock(DCL)
通過單例模式生產類是程序員必會,它有很多寫法,其中的懶漢式,及延遲生成類,應使用雙重檢查,否則就會出現生成多例:
public class Singleton {
private static Singleton singleton;
private Singleton() {}
public Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class){
if(singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
以上代碼看起來似乎以及完美了,但是其實還有漏洞。如下:
實例化一個對象要分為三個步驟:
- 分配內存空間
- 初始化對象
- 將內存空間的地址賦值給對應的引用
但是由於重排序的緣故,步驟2、3可能會發生重排序,其過程如下:
- 分配內存空間
- 將內存空間的地址賦值給對應的引用
- 初始化對象
如果2、3發生了重排序就會導致第二個判斷會出錯,singleton != null,但是它其實僅僅只是一個地址而已,此時對象還沒有被初始化,所以return的singleton對象是一個沒有被初始化的對象。
解決方法是在一處加上關鍵字:
private volatile static Singleton singleton; //1
這樣就保證了變量singleton的可見性,使得程序能到達到我們的預期。
參考資料: