單例模式和雙重檢測的小結

2021-07-04 08:56:49 字數 1387 閱讀 5759

設計模式的經典模式之一——單例模式

這個也是面試經常被問起的面試,一般都要求手寫

【餓漢模式】非延時載入 ——以空間換時間

【懶漢模式】延時載入——以時間換空間

看似簡單,但是在懶漢模式還隱藏了乙個雙重檢測,其中還是涉及到jvm記憶體的「無序寫入」問題(後面使用的 volatile )

比較簡單,非延時載入,一上來就把物件給new出來了

public class singleton  //預設構造器

private static singleton instance = new singleton();//直接載入

public singleton getintance()

}

public class singleton  // 預設構造器

private static singleton instance = null;// 延時載入

//每次執行都要建立例項因而需要加鎖保護

public static synchronized singleton getintance()

return instance;

}}

上面儘管這樣做到了執行緒安全,並且解決了多例項問題,但並不高效。在任何呼叫這個方法的時候,你都需要承受同步帶來的效能開銷,然而同步只在第一次呼叫的時候才被需要,也就是單例類例項建立的時候。這將促使我們使用雙重檢查鎖模式(double checked locking pattern),一種只在臨界區**加鎖的方法。一般稱其為雙重檢查鎖,因為會有兩次檢查 _instance == null,一次不加鎖,另一次在同步塊上加鎖。

public class singleton  // 預設構造器

private volatile static singleton instance = null;// volatile 可見性/防止重排序

public static singleton getintance()

}} return instance;

}}

如果使用雙重檢查鎖定來實現懶漢式單例類,需要在靜態成員變數instance之前增加修飾符volatile(可見性,防止重排序),被volatile修飾的成員變數可以確保多個執行緒都能夠正確處理,且該**只能在jdk 1.5及以上版本中才能正確執行。

public class singleton  

} public static singleton createsingleton()

} }

}

threadlocal的全域性變數區域性化 第一次檢測採用執行緒區域性來做如果執行緒已經訪問過則不需要進入同步塊

雙重檢測單例模式

在多執行緒場景下,當乙個執行緒判斷instance為null時 他會新建乙個例項,那麼問題來了,當a執行緒發現物件例項為空時,準備 新建乙個例項,這時cpu輪詢到b執行緒,b執行緒也察覺物件例項為空,它也會新建乙個例項,這樣就破壞了單例模式。首先物件例項必須是全域性共享的,用volatile修飾,然...

雙重檢測鎖單例模式指令重排問題

解決方案 相信大多數同學在面試當中都遇到過手寫單例模式的題目,那麼如何寫乙個完美的單例是面試者需要深究的問題,因為乙個嚴謹的單例模式說不定就直接決定了面試結果,今天我們就要來講講看似執行緒安全的雙重檢測鎖單例模式中可能會出現的指令重排問題。乍一看下面單例模式沒啥問題,還加了同步鎖保證執行緒安全,從表...

單例模式的雙重檢測鎖與volatile禁止重排

public class demo public static demo getinstance return instance 上面單例實現方式在單執行緒訪問下沒有問題,但是在併發訪問時,會產生多個物件。如程式啟動 a執行緒獲取instance執行完if判斷為null後,執行緒b獲取到cpu執行權...