剛剛寫完靜態**塊問題,突然想到之前單例模式的坑,雖然解決辦法知道了,但是之前的原理不太明白,剛剛突然想清楚了。。。
感謝大神
//餓漢式
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...