1. 程式人生 > >Java設計模式--單例模式

Java設計模式--單例模式

提高 安全問題 color 自動 如果 排序 get 重排序 col

直想寫點關於設計模式的東西,卻懶到現在都沒寫過什麽,今天上午看到項目中的代碼,就在這個中午抽出時間寫點東西,拋個項目截圖先:

技術分享圖片

單例模式:

單例模式,是一種常用的軟件設計模式。在它的核心結構中只包含一個被稱為單例的特殊類。通過單例模式可以保證系統中,應用該模式的類一個類只有一個實例。即一個類只有一個對象實例。

下面介紹Java中常用的單例模式:

一、懶漢模式

技術分享圖片

這種寫法看上去似乎實現了單例模式,然鵝、實際應用中卻不實用,盡管我所在的項目中有著類似的代碼,我也不得不說確實如此;

優點:實現了按需創建,即懶加載

缺點:線程不安全。在多線程案例中,這種方式並沒有完全實現單例模式。例如當多個線程訪問getSingleton方法時,一起判斷null == singleton,這時就會創建多個Singleton的實例。

實現了線程安全的懶漢模式(兩種方式寫法不同,卻是一致的):

技術分享圖片

技術分享圖片

上面兩種寫法雖有差異,但運行效果卻是相同的;

優點:解決了多線程的安全問題

缺點:效率卻低的不要不要的。因為每當有線程訪問時,就會出現線程排隊等候,真正去創建實例的線程只有一個。

技術分享圖片

現實中也有人通過添加volatile關鍵字對對象實例進行限制,volatile保證其對所有線程的可見性,並且禁止對其進行指令重排序優化。

下面介紹下兼顧線程安全與效率的懶漢模式:

技術分享圖片

這種方式被稱為雙重檢查鎖/雙重校驗鎖方式,通過兩次判null操作,它解決了線程安全的問題,不會創建多個實例。同時、也提高了線程訪問的效率問題。這種方式可以算作是懶漢模式的最優解,但並非單例模式的最優解。

二、餓漢模式

技術分享圖片

優點:寫法簡單,一目了然

缺點:無法做到按需創建,即懶加載,增加負載。

註意:這裏的增加負載要看具體情況,就上面的代碼而言,new一個Singleton實例,算不上增加負載,但如果你new的是一個很大的對象,這時你應該考慮這個問題了。

三、靜態內部類

技術分享圖片

把Singleton實例放到一個靜態內部類中,這樣就避免了靜態實例在Singleton類加載的時候就創建對象,並且由於靜態內部類只會被加載一次,所以這種寫法也是線程安全的。

優點:線程安全,按需創建。

缺點:1、需要額外的工作(Serializable、transient、readResolve())來實現序列化,否則每次反序列化一個序列化的對象實例時都會創建一個新的實例。

   2、可能會有人使用反射強行調用我們的私有構造器(如果要避免這種情況,可以修改構造器,讓它在創建第二個實例的時候拋異常)。

四、枚舉

技術分享圖片

使用枚舉除了線程安全和防止反射強行調用構造器之外,還提供了自動序列化機制,防止反序列化的時候創建新的對象。因此,Effective Java推薦盡可能地使用枚舉來實現單例。

最後,不管采取何種方案,請時刻牢記單例的三大要點:

  • 線程安全
  • 延遲加載
  • 序列化與反序列化安全

Java設計模式--單例模式