詳解Java設計模式:單例模式

詳解設計模式:單例模式

設計模式之單例模式

前言:

單例模式,對我們來說不陌生。有些時候,我們想要一個類在整個系統中僅存在一個實例。比如說,系統給我們提供了一個打印機硬件設施,但是我們在系統中多次new 打印機,創建出多個打印機的實例去完成打印任務,那麼這個時候就會出現資源衝突現象,這就要求我們必須想一個辦法,去確保系統中存在唯一的一個打印機實例。

解決的方式有很多,例如創建一個全局變量:


這樣創建一個全局變量,並且規定想要使用打印機服務,必須使用mPrinter 這個實例去完成,不得再去創建新的打印機實例,這種方法是可以解決這個問題的。但是這種方法是有缺陷的,比如,一些不遵守規則的人或者說不明白規則的人又創建了一個Printer實例,還是會引起衝突,這就出現了單例模式。

1單例模式


如圖示,如若我們將單例模式的構造方法設置成private,也就是私有的,只提供給一個獲得實例的接口,並且在getInstance 方法中做些特殊處理,就可以保證系統中存在唯一實例,下面介紹幾種單例模式的實現方法。


  • 經典實現方法(懶漢式)


通過這種定義方法,就可以保證系統中僅存在唯一實例,是嗎?
一般情況下,這種方式是不會存在問題的,但是因爲多線程,導致這種方法是不可靠的。舉例來說,如果系統中存在兩個子線程,同時進入 getInstance() 函數,當一個線程剛剛通過if判斷語句,還未來得及 new 出一個實例,線程切換,另一個線程也通過了if判斷語句,那麼這個時候就會new出兩個實例,還是無法保證在多線程條件下的單一性,所以我們需要在getInstance() 函數前加入 synchronized 關鍵字。

synchronized 處理,可以保證同一時刻,只有一個線程可以進入getInstance() 函數,但是如果我們需要多次調用getInstance() 函數時,這種方法是非常消耗資源的。當然,如果我們只是很少次使用這個函數,那麼這種方法是完全滿足需求的。那麼針對多次使用的情況,我們只能使用下一種方式了。


  • 餓漢式


這種方法我們直接在定義的時候就 new 出了一個實例,無論調用getInstance() 多少次,我們也只會返回固定的一個實例,也就不存在多線程同步的問題了。

但是,如果我們從頭到位並沒有用到 Printer ,而我們卻草率的 new 出了一個實例,這樣會佔用內存資源,所以我們還要用到下一種方法。


  • 雙重檢查鎖定


當一個線程通過第一個if判斷語句時,無論怎樣,在同一時刻,只有一個線程可以進入第二個if判斷語句,而且會new 出一個實例,保證synchronized方法從始至終只會執行一次,這樣就解決了餓漢式和懶漢式的尷尬,因爲它既不會像懶漢式那樣多次進入synchronized方法佔用系統資源,也不會像餓漢式那樣在不使用的情況下佔用系統資源。


  • 一種更好的實現方法

事實上還存在一種能夠將餓漢式和懶漢式的缺點全部克服而且能將二者的優點合二爲一的方法,那就是 Initialization on Demand Holder(IoDH)方法。


因爲靜態的單例對象沒有作爲類的成員變量直接實例化,因此在Printer類加載時並沒有實例化mPrinter。第一次調用newInstance() 的時候加載內部類CreatePrinter ,該內部類定義了一個static 類型的變量mPrinter,此時會首先初始化這個變量,由JVM 來保證其線程安全性,確保該成員變量只被實例化一次。
可見,通過使用這個方法,不僅實現了延遲加載,又可以保證線程安全,不影響系統性能。

好了,教程到這裏就結束了。如果你學到了,麻煩評論、頂下,給博主一個鼓勵,謝謝啦~~~~~(>_<)~~~~


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