單例單例,就是只允許例項化乙個物件。一般實現方式也就是將構造方法私有化,然後對外暴露乙個獲取例項的介面
單例 可以說源自於設計模式中的單例模式吧,多種實現演進,變得越來越靠譜
最早單例模式分為懶漢式 餓漢式
懶漢式:
懶漢式很簡單啊,就是全域性變數宣告時候直接new了,但是這樣會有個占用記憶體的問題,因為如果這個例項用不到,那不是白白浪費空間了,尤其是專案龐大寸土寸金的jvm記憶體空間
懶漢式的有點也很明顯,簡單好用,而且不會有亂七八糟的執行緒安全問題,所以單例的這個例項一定會用到的話 用懶漢式直接實現也無妨
餓漢式:
最原始的餓漢式,外部獲取例項的時候先判斷 例項是不是null,如果空的直接new乙個
單執行緒的世界裡這樣搞絕對沒問題,但是問題就出在了多執行緒的情況下,當多個執行緒同時呼叫getinstance() ,然後同時判斷了singlon為null,也就會new兩個例項出來,違反了單例。
怎麼辦呢,為了多執行緒安全 那就加鎖唄
這下放心了,多執行緒來呼叫這個方法的時候,不許搶都得給我排隊序列來執行,也就保證了只會new一次singlon
但是還有問題,synchronized 這麼重量級的鎖 直接加到了這個方法上是不是不太好啊,如果多個執行緒經常頻繁的會呼叫這個方法,都序列執行那也太難受了 (即時jdk1.8 後synchronized會有鎖公升級)
so 盡量輕量一點 只在if條件確定了singlon==null的時候 再加鎖行不行?
if(singlon == null){
synchronized(this){
singlon = new singlon();
不行啊,如果恰好就有兩個同時判斷了singlon == null 然後同時進入到了if的**塊,加鎖並沒有阻止第二個執行緒new singlon啊
應運而生了double-check 一次判斷不夠用 我再來一次被
在鎖裡在判斷一次 這下放心了吧
以為到這萬事大吉了,其實並不然.雖然這種情況發生的概率不大,指令重排序導致的多執行緒安全問題
singlon = new singlon(); 這一行** 在底層其實是三條指令完成的
1.開闢一塊堆記憶體空間
2. 初始化乙個singlon物件
3. singlon宣告指向這個物件
由於指令重排,很有可能 2 3步進行重排,1 3 2 的順序執行,
但第乙個執行緒執行完了1 3步,這個時候,第二個執行緒進入方法 判斷了一下singlon不為null 就直接返回了,事實上這個 singlon表面上不為null 但是還沒來得及實實在在的例項化,導致直接return出問題
那咋辦呢 加volatile 防止指令重排唄
實現單例的方式還有很多 比如常用的靜態內部類靜態**塊或者更簡單直接用列舉它不香嗎? 這裡就不一一枚舉了 over
單例模式 DoubleCheck
1.單例模式理解 是為了滿足一些場景,乙個物件只能建立乙個例項物件的場景。流程 1.構造方法私有化,2.宣告物件 位靜態 3.類方法返回例項化後的物件。2.將單例模式分為兩類 懶漢式和餓漢式 懶漢式 特點在定義singleton是就new public class singleton public ...
單例模式與double check
本文主要是講double check,通常double check比較少用,一般是在高併發的情況下。但是建議大家寫單例的時候都用上。單例模式分兩種 餓漢式與懶漢式,餓漢式是指在類載入時就進行例項化,而懶漢式是指在使用時才進行例項化。如下 餓漢式 public class singleton publ...
設計模式單例模式之double check
設計模式之雙重判定鎖 double check 下面列出乙個比較常用的也是我個人最喜歡的一種在多執行緒的情況下,又能滿足lazy loading,效率又高的一種單例模式的寫法 class singleton 在這可能有些小夥伴會問這個volatile這個是幹啥的,給出答案 volatile這個關鍵字...