淺析設計模式:單例模式(Songleton)

    在實際編程中,我們可能有這樣的需求:確保某個類在Java堆內存中只存在一個實例,這樣的場景一般出現在該類實例作爲控制器,或者在GUI編程中的視圖窗口。

    本文介紹單例模式的4中常用實現方式,並分析它們各自的優缺點:

1)、餓漢式



    餓漢式實現簡單,能夠滿足大部分應用場景,即使是在併發環境下也能夠保證單例模式的正確性。

    但是餓漢式也存在一些弊端:餓漢式的實例在類加載的初始化階段就完成實例化,這也許過早了點,因爲程序中若不使用或者在較晚階段纔會使用該實例的話,過早的實例化可能會造成資源不必要的浪費,系統啓動時間也會有所影響。


2)、懶漢式


     這是最原始的懶漢式,與餓漢式的區別在於,靜態屬性instance一開始並未實例化,因此在類加載階段也就不會加載到內存中。其次,在getInstance靜態方法中判斷instance是否被實例化了,若未實例化則創建,否則直接返回,因此instance屬性的實例化延遲到了運行期才完成,這很好的節省了系統的資源。

     當然,這種原始的懶漢式也存在明顯的弊端,若在併發環境下,getInstance靜態方法可能會"同時"被多個線程訪問,因此創建多個實例,這就背離了單例模式。因此需要對原始的懶漢式進行改進:


只需要在原來的基礎上作兩點改進:

1、使用volatile關鍵字修飾靜態屬性instance

2、對getInstance靜態方法雙重校驗鎖優化

     優化後的懶漢式就可以滿足併發環境的要求了,但是使用synchronize同步代碼塊可能會影響性能,可以使用ReentrantLock替代。


3)、靜態內部類式


    靜態內部類式是一種比較推薦的方式,程序運行時調用getInstance靜態方法時,內部類纔會被加載到JVM內存中,因此實例化的過程也就被延遲到了運行期。再者,利用JVM類加載機制自身的特性(類構造器<cinit>只會被調用一次),使得即使在併發環境下也能保證只會創建一個實例。

4)、使用枚舉


使用枚舉實現單例模式是Effective Java作者Josh Bloch 提倡的方式,解決了以下三個問題:
(1)自由序列化。
(2)保證只有一個實例。
(3)線程安全。

    上述的4中實現單例模式的方式已經介紹完畢,如何去抉擇還是應當考慮具體的情況,需要特別指出的是,這幾中方式並不能真正100%的保障只存在一個實例,因爲java語言中創建對象的方式可不只有new,通過反射一樣可以進行實例化,因此在使用單例模式時還是需要儘量避免使用反射,下面提供一個例子,講解如何使用反射機制破解單例模式:



Ending ...大笑



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章