Java中線程安全的單例模式

2021-08-31 03:30:16 字數 1603 閱讀 9744

chen_gangl

104人閱讀

2013-07-25 11:23:13

寫出乙個單例模式(singleton pattern)

public final class eagersingleton 

public static eagersingleton getsingleinstance() 

} 這種寫法就是所謂的飢餓模式,每個物件在沒有使用之前就已經初始化了。這就可能帶來潛在的效能問題:如果這個物件很大呢?沒有使用這個物件之前,就把它載入到了記憶體中去是一種巨大的浪費。針對這種情況,我們可以對以上的**進行改進,使用一種新的設計思想——延遲載入(lazy-load singleton)。

public final class lazysingleton 

public static lazysingleton getsingleinstance() 

} 這種寫法就是所謂的懶漢模式。它使用了延遲載入來保證物件在沒有使用之前,是不會進行初始化的。這種寫法執行緒安全嗎?不安全。這是因為在多個執行緒可能同時執行到if(null == singobj),判斷singobj為null,於是同時進行了初始化。所以,這是面臨的問題是如何使得這個**執行緒安全?很簡單,在那個方法前面加乙個synchronized就ok了。

public final class threadsafesingleton 

public staticsynchronizedthreadsafesingleton getsingleinstance() 

} 這個寫法有沒有什麼效能問題呢?答案肯定是有的!同步的代價必然會一定程度的使程式的併發度降低。那麼有沒有什麼方法,一方面是執行緒安全的,有可以有很高的併發度呢?

我們觀察到,執行緒不安全的原因其實是在初始化物件的時候,所以,可以想辦法把同步的粒度降低,只在初始化物件的時候進行同步。這裡有必要提出一種新的設計思想——雙重檢查鎖(double-checked lock)。

public final class doublecheckedsingleton 

public static doublecheckedsingleton getsingleinstance()

14       }

15       return singobj;

} } 

這種寫法使得只有在載入新的物件進行同步,在載入完了之後,其他執行緒在第九行就可以判斷跳過鎖的的代價直接到第15行**了。做到很好的併發度。

上面的寫法一方面實現了lazy-load,另乙個方面也做到了併發度很好的執行緒安全,一切看上很完美。其實這種寫法還是有問題的!問題在**?假設執行緒a執行到了第9行,它判斷物件為空,於是執行緒a執行到第12行去初始化這個物件,但初始化是需要耗費時間的,但是這個物件的位址其實已經存在了。此時執行緒b也執行到了第九行,它判斷不為空,於是直接跳到15行得到了這個物件。但是,這個物件還沒有被完整的初始化!得到乙個沒有初始化完全的物件有什麼用!關於這個double-checked lock的討論有很多,目前公認這是乙個anti-pattern,不推薦使用!

C 中線程安全的單例模式

這是從公司內網上轉過來的,總結的不錯,就記錄了,這裡默默感謝下。一 即第一次呼叫該類例項的時候才產生乙個新的該類例項,並在以後僅返回此例項。需要用鎖,來保證其執行緒安全性 原因 多個執行緒可能進入判斷是否已經存在例項的if語句,從而non thread safety.使用double check來保...

Spring中線程安全的單例模式原始碼分析

最近學習spring aop原始碼時,看到了spring原始碼中十分驚豔的乙個執行緒安全類,所以特意記錄下來。public abstract class globaladvisoradapterregistry 重置單例物件 static void reset 分析這段原始碼前,首先得介紹一下單例模...

java單例安全模式

關於單例模式的文章,其實網上早就已經氾濫了。但乙個小小的單例,裡面卻是有著許多的變化。網上的文章大多也是提到了其中的乙個或幾個點,很少有比較全面且脈絡清晰的文章,於是,我便萌生了寫這篇文章的念頭。企圖把這個單例說透,說深入。但願我不會做的太差。首先來看乙個典型的實現 複製 1 2 基礎的單例模式,l...