執行緒安全的單例模式
面試的時候,常常會被問到這樣一個問題:請您寫出一個單例模式(Singleton Pattern)吧。好吧,寫就寫,這還不容易。順手寫一個:
- public final class EagerSingleton
- {
- private static EagerSingleton singObj = new EagerSingleton();
- private EagerSingleton(){
- }
- public static EagerSingleton getSingleInstance(){
- return singObj;
- }
- }
這種寫法就是所謂的 飢餓模式,每個物件在沒有使用之前就已經初始化了。這就可能帶來潛在的效能問題:如果這個物件很大呢?沒有使用這個物件之前,就把它載入到了記憶體中去是一種巨大的浪費。針對這種情況,我們可以對以上的程式碼進行改進,使用一種新的設計思想—— 延遲載入(Lazy-load Singleton)。
- public final class LazySingleton
- {
- private static LazySingleton singObj = null;
- private LazySingleton(){
- }
- public static LazySingleton getSingleInstance(){
- if(null == singObj ) singObj = new LazySingleton();
- return singObj;
- }
- }
這種寫法就是所謂的 懶漢模式。它使用了延遲載入來保證物件在沒有使用之前,是不會進行初始化的。但是,通常這個時候面試官又會提問新的問題來刁難一下。他會問:這種寫法執行緒安全嗎?回答必然是:不安全。這是因為在多個執行緒可能同時執行到第九行,判斷singObj為null,於是同時進行了初始化。所以,這是面臨的問題是如何使得這個程式碼執行緒安全?很簡單,在那個方法前面加一個Synchronized就OK了。
- public final class ThreadSafeSingleton
- {
- private static ThreadSafeSingleton singObj = null;
- private ThreadSafeSingleton(){
- }
- public static Synchronized ThreadSafeSingleton getSingleInstance(){
- if(null == singObj ) singObj = new ThreadSafeSingleton();
- return singObj;
- }
- }
寫到這裡,面試官可能仍然會狡猾的看了你一眼,繼續刁難到:這個寫法有沒有什麼效能問題呢?答案肯定是有的! 同步的代價必然會一定程度的使程式的併發度降低。那麼有沒有什麼方法,一方面是執行緒安全的,有可以有很高的併發度呢?我們觀察到,執行緒不安全的原因其實是在初始化物件的時候,所以,可以想辦法把同步的粒度降低,只在初始化物件的時候進行同步。這裡有必要提出一種新的設計思想—— 雙重檢查鎖(Double-Checked Lock)。
- public final class DoubleCheckedSingleton
- {
- private static DoubleCheckedSingletonsingObj = null;
- private DoubleCheckedSingleton(){
- }
- public static DoubleCheckedSingleton getSingleInstance(){
- if(null == singObj ) {
- Synchronized(DoubleCheckedSingleton.class){
- if(null == singObj)
- singObj = new DoubleCheckedSingleton();
- }
- }
- return singObj;
- }
- }
這種寫法使得只有在載入新的物件進行同步,在載入完了之後,其他執行緒在第九行就可以判斷跳過鎖的的代價直接到第15行程式碼了。做到很好的併發度。
至此,上面的寫法一方面實現了Lazy-Load,另一個方面也做到了併發度很好的執行緒安全,一切看上很完美。這是,面試官可能會對你的回答滿意的點點頭。但是,你此時提出說,其實這種寫法還是有問題的!!問題在哪裡?假設執行緒A執行到了第9行,它判斷物件為空,於是執行緒A執行到第12行去初始化這個物件,但初始化是需要耗費時間的,但是這個物件的地址其實已經存在了。此時執行緒B也執行到了第九行,它判斷不為空,於是直接跳到15行得到了這個物件。但是,這個物件還 沒有被完整的初始化!得到一個沒有初始化完全的物件有什麼用!!關於這個Double-Checked Lock的討論有很多,目前公認這是一個Anti-Pattern,不推薦使用!所以當你的面試官聽到你的這番答覆,他會不會被Hold住呢?
那麼有沒有什麼更好的寫法呢?有!這裡又要提出一種新的模式—— Initialization on Demand Holder. 這種方法使用內部類來做到延遲載入物件,在初始化這個內部類的時候,JLS(Java Language Sepcification)會保證這個類的執行緒安全。這種寫法最大的美在於,完全使用了Java虛擬機器的機制進行同步保證,沒有一個同步的關鍵字。
- public class Singleton
- {
- private static class SingletonHolder
- {
- public final static Singleton instance = new Singleton();
- }
- public static Singleton getInstance()
- {
- return SingletonHolder.instance;
- }
- }
至此,本文完。提供一些連結For your reference:
Double-Checked Lock: http://en.wikipedia.org/wiki/Double-checked_locking
Initialzation on Demand Holder: http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom
原文地址:
相關文章
- C++ 執行緒安全的單例模式C++執行緒單例模式
- 設計模式之單例模式(執行緒安全)設計模式單例執行緒
- 單例模式——執行緒安全的兩種實現單例模式執行緒
- 你的單例模式真的是執行緒安全的嗎?單例模式執行緒
- 【設計模式】實現執行緒安全單例模式的五種方式設計模式執行緒單例
- 如何看待Spring下單例模式與執行緒安全的矛盾Spring單例模式執行緒
- JAVA_多執行緒_單例模式Java執行緒單例模式
- ios中的執行緒安全單例實現iOS執行緒單例
- C++ 靜態變數單例模式的誤會(執行緒安全)C++變數單例模式執行緒
- 靜態內部類實現的單例模式是執行緒安全的單例模式執行緒
- 單例模式(上)—如何優雅地保證執行緒安全問題單例模式執行緒
- 單例模式(上)---如何優雅地保證執行緒安全問題單例模式執行緒
- 單例模式(含執行緒鎖關鍵字)單例模式執行緒
- 單例模式中可能存在的一些問題(執行緒安全問題)單例模式執行緒
- 多執行緒下的單例執行緒單例
- 設計模式-單例模式之餓漢式-多執行緒設計模式單例執行緒
- 設計模式-單例模式之懶漢式-多執行緒設計模式單例執行緒
- 多執行緒安全的單例模式(使用判斷nullptr和call_once兩種方法)執行緒單例模式Null
- synchronized 同步執行緒 單例設計模式+double checkingsynchronized執行緒單例設計模式
- java多執行緒結合單例模式例項,簡單實用易理解Java執行緒單例模式
- python 執行緒安全的 單例 實現 日誌分級Python執行緒單例
- C++實現一個執行緒安全的單例工廠C++執行緒單例
- Java多執行緒程式設計筆記10:單例模式Java執行緒程式設計筆記單例模式
- 執行緒安全的觀察者模式的設計執行緒模式
- ios-UI高階多執行緒 GCD實現單例模式iOSUI執行緒GC單例模式
- 【Java多執行緒】執行緒安全的集合Java執行緒
- 執行緒3--執行緒安全執行緒
- 不使用synchronized和lock,如何實現一個執行緒安全的單例?synchronized執行緒單例
- muduo網路庫學習筆記(6):單例類(執行緒安全的)筆記單例執行緒
- 執行緒安全和執行緒不安全理解執行緒
- 關於JSP 例項方法的執行緒安全JS執行緒
- 執行緒安全執行緒
- 24. 一個普通main方法的執行,是單執行緒模式還是多執行緒模式?為什麼?AI執行緒模式
- PHP的執行緒安全與非執行緒安全版本的區別PHP執行緒
- linux執行緒池簡單例項Linux執行緒單例
- singleton模式四種執行緒安全的實現模式執行緒
- 多執行緒系列之 執行緒安全執行緒
- iOS 多執行緒之執行緒安全iOS執行緒