本文將**單例模式的各種情況,並給出相應的建議。 單例模式應該是設計模式中比較簡單的乙個,但是在多執行緒併發的環境下使用卻是不那麼簡單了。
首先看最原始的單例模式。
顯然這個寫法在單執行緒環境下非常好,但是多執行緒會導致多個例項出現,這個大家都能理解。
最簡單的改造方式是新增乙個同步鎖。
顯然上面的方法避免了併發的問題,但是由於我們只是在第一次構造物件的時候才需要同步,以後就不再需要同步,所以這裡不可避免的有效能開銷。
於是將鎖去掉採用靜態的屬性來解決同步鎖的問題。
上面的方法既沒有鎖又解決了效能問題,看起來已經滿足需求了。但是追求「完美」的程式設計師想延時載入物件,希望在第一次獲取的時候才構造物件,於是大家非常聰明的進行改造,也即非常出名的雙重檢查鎖機制出來了。
雙重鎖機制看起來非常巧妙的避免了上面的問題。但是真的是這樣的嗎?文章《雙重檢查鎖定及單例模式》中談到了非常多演變的雙重檢查鎖機制帶來的問題,包括比較難以理解的指令重排序機制等。總之就是雙重鎖機制仍然對導致錯誤問題而不是效能問題。
於是繼續改造,某個牛人利用jvm的特性來解決上述問題。
上述**看起來解決了上面單例模式遇到的所有問題,而且實際上工作的很好,沒有什麼問題。但是卻有乙個致命的問題,如果第11行丟擲了乙個異常,也就是第一次建構函式失敗將導致永遠無法再次得到構建物件的機會。
使用下面的**測試下。
很顯然我們想著第一次載入失敗第二次能夠載入成功,非常不幸,jvm一旦載入某個類失敗將認為此類的定義有問題,將來不再載入,這樣就導致我們沒有機會再 載入。目前看起來沒有辦法避免此問題。如果要使用jvm的類載入特性就必須保證類載入一定正確,否則此問題將比併發和效能更嚴重。如果我們的類需要初始話 那麼就需要想其它辦法避免在建構函式中完成。看起來像是又回到了老地方,難道不是麼?
總之,結論是目前沒有乙個十全十美的單例模式,而大多數情況下我們只需要滿足我們的需求就行,沒必有特意追求最「完美」解決方案。
單例模式解析
1 餓漢模式 優點 在類初始化時已經例項化完成,呼叫時較快 執行緒安全 缺點 不管後期是否使用,都進行了一次初始化,有可能浪費資源 public class singleton 建構函式私有化 public static singleton getinstance 2 懶漢模式 不推薦 優點 只有在...
單例模式解析
什麼是單例模式?在整個jvm執行週期中只有乙個例項的物件。用法 執行緒安全 double check public void class singleton 3.實現雙重檢查鎖構造單例 public singleton getinstance return instance 為什麼要使用雙重檢查鎖?...
解析單例模式(1)
什麼是單例模式 保證乙個類只有乙個例項,並且對外提供乙個全域性訪問點 單例模式意義 單例模式可以嚴格控制客戶怎麼訪問以及何時訪問。單例模式的注意點 可以被繼承,單例模式是有狀態的 public class singletest 私有建構函式保證不能通過建構函式生成類物件 public static ...