單例模式製造獨一無二的對象

爲什麼使用單例模式(why)

爲什麼不用靜態全局變量呢?如果將對象賦值給全局變量,那麼你必須在程序一開始就創建對象,非常消耗資源。利用單例模式,就可以在需要的時候才創建對象。另外全局變量可能指向多個對象,這違反了實例唯一性。

什麼是單例模式(what)

單例模式確保一個類有且僅有一個實例,並提供一個全局變量。類圖如下:
在這裏插入圖片描述
單例模式典型例子強調三點:1、定義私有靜態全局變量,2、私有化構造器,3、用getInstance()方法實例化對象,並返回這個實例。

線程不安全的懶漢式

代碼如下:
在這裏插入圖片描述

不同場景下使用單例模式(where)

線程安全的懶漢式

但是,如果遇到多線程,那麼上述代碼的實例對象就不是唯一的了。就如同下圖所示情況,實例化了兩個對象。
在這裏插入圖片描述
我們可以把getInstance方法變成synchronized方法,如下代碼所示:
在這裏插入圖片描述
然而同步會降低性能,另外只有第一次執行此方法時,才需要同步。換句話說,一旦設置好uniqueIinstance變量,就不再需要同步方法了,之後每次調用這個方法都是一種累贅。
不同場景下,你需要做出選擇,如果getInstance()的性能不是很關鍵,那麼使用同步方法無可厚非。但你需要知道的是:同步一個方法會造成程序執行效率下降100倍。因此getInstance()使用頻繁的場景就不能使用同步方法了。

餓漢式

這時候如果在創建和運行時方面的負擔不太繁重,你可以在靜態初始化器中創建單例,這保證了線程安全。我們依賴JVM在加載這個類時馬上創建單例。JVM保證在任何線程訪問uniqueInstance靜態變量之前,一定先創建此實例。代碼如下:
在這裏插入圖片描述

DCL方式(double-checked locking雙重檢查加鎖)

如果性能是你關注的重點,那麼你可以採用DCL來幫你大大減少getInstance()的耗時,該方法首先檢查實例是否已經創建,如果尚未創建才同步。
volatile關鍵字保證了高併發下其被創建後會立即更新到JVM主存中,其被讀取也是線程立即到主存中去讀取,而不經過線程的緩存,保證了實例的狀態在任何時刻都是最新的,volatile關鍵字的作用詳見volatile關鍵字的作用
在這裏插入圖片描述

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