單例模式的DCL問題

2021-07-24 22:40:44 字數 1624 閱讀 4558

剛剛寫完靜態**塊問題,突然想到之前單例模式的坑,雖然解決辦法知道了,但是之前的原理不太明白,剛剛突然想清楚了。。。

感謝大神

//餓漢式

class single //私有化建構函式。

private static single s = new single(); //建立私有並靜態的本類物件。

public static single getinstance()

}

延遲載入方式

class single2

private static single2 s = null;

public static single2 getinstance()

}

class single 

public static single getinstance()

}return s;}}

好了  寫到這個大家認為應該沒什麼問題了對吧,但事實不是,有乙個很隱蔽的bug!!!

new instance()到底發生了什麼?

memory = allocate(); //1:分配物件的記憶體空間

ctorinstance(memory); //2:初始化物件

instance = memory; //3:設定instance指向剛分配的記憶體位址

上面的偽**中2、3步可能重排

執行緒a   已經把 new出來的物件給了instance  但是裡面的屬性還沒有初始化  ,然後這個時候b 執行緒來了  判斷 instance已經不為null(已經分配了記憶體位址),但是裡面的屬性還沒初始化,所以問題就出現了

原理:

在類的初始化期間,jvm會去獲取乙個鎖。這個鎖可以同步多個執行緒對同乙個類的初始化。

餓漢式

public class instanceholder 

}

這種寫法不會出現併發問題,但是它是餓漢式的,在classloader載入類後instanceholder的

例項就會第一時間被建立,餓漢式的建立方式在一些場景中將無法使用:譬如instanceholder例項的建立是依賴引數或者配置檔案的,在getinstance()之前必須呼叫某個方法設定引數給它,那樣這種單例寫法就無法使用了。 

懶漢式

public class instanceholder 

//lazy initialization holder class idiom for static fields

private static class inner

public static instance getinstance()

}

由於inner是私有的,除了getinstance()之外沒有辦法訪問它,因此它是懶漢式的;同時讀取例項的時候不會進行同步

初始化乙個類,包括執行這個類的靜態初始化(static**段)和初始化在這個類中宣告的靜態字段。

dcl單例模式

有時候我們需要對外呈現只有乙個物件,簡單來說就是講物件私有化,像資料那樣,只能通過get方法得到。這裡使用doublechecking來進行該操作,即在get方法裡面加入兩個判斷該物件是否為空,同時為了避免指令重排導致執行緒獲得空物件,加入volatile,而且私有化構造器。public class...

DCL單例模式

單例模式 外部不能new物件,類的內部有且只有乙個物件,僅僅用乙個靜態方法與外界進行互動。public class doublecheckedlocking 外部只能通過這個get方法和此物件進行交流 public static doublecheckedlocking getinstance 繫結...

多執行緒 DCL單例模式

package others dcl單例模式 懶漢式套路基礎上加入併發控制,保證在多執行緒環境下,對外存在乙個物件 1 構造器私有化 避免外部new構造器 2 提供私有的靜態屬性 儲存物件的位址 3 提供公共的靜態方法 獲取屬性 author public class doublecheckedlo...