- 重學Java設計模式
- 付政委(小付哥)
- 1291字
- 2021-05-19 18:10:06
8.4 七種單例模式實現方式
單例模式的實現方式比較多,主要分為在實現上是否支持懶漢模式,是否支持在線程安全中運用各項技巧。當然,也有一些場景不需要考慮懶漢模式的情況,會直接使用static靜態類或屬性和方法的方式,供外部調用。
接下來通過不同方式的實現,講解單例模式。
8.4.1 靜態類使用


這種靜態類方式在日常的業務開發中很常見,它可以在第一次運行時直接初始化Map類,同時也不需要直到延遲加載再使用。在不需要維持任何狀態的情況下,僅僅用于全局訪問,使用靜態類方式更加方便。在需要被繼承及維持一些特定狀態的情況下,適合使用單例模式。
8.4.2 懶漢模式(線程不安全)

單例模式有一個特點是不允許外部直接創建,也就是 new Singleton_01(),因此這里在默認的構造函數上添加了私有屬性private。雖然采用此種方式的單例滿足了懶漢模式,但是如果有多個訪問者同時獲取對象實例,就會造成多個同樣的實例并存,沒有達到單例的要求。
8.4.3 懶漢模式(線程安全)

此種模式雖然是安全的,但由于把鎖加到方法中后,所有的訪問因為需要鎖占用,導致資源浪費。除非在特殊情況下,否則不建議用此種方式實現單例模式。
8.4.4 餓漢模式(線程安全)

這種方式與開頭的第一個實例化 Map 基本一致,在程序啟動時直接運行加載,后續有外部需要使用時獲取即可。這種方式并不是懶加載,也就是說無論程序中是否用到這樣的類,都會在程序啟動之初進行創建。這種方式造成的問題就像一款游戲軟件,可能游戲地圖還沒有打開,但是程序已經將這些地圖全部實例化。在手機上最明顯的體驗就是打開游戲提示內存滿了,造成手機卡頓。
8.4.5 使用類的內部類(線程安全)

使用類的靜態內部類實現的單例模式,既保證了線程安全,又保證了懶漢模式,同時不會因為加鎖而降低性能。這主要是因為JVM虛擬機可以保證多線程并發訪問的正確性,也就是一個類的構造方法在多線程環境下可以被正確地加載。這也是推薦使用的一種單例模式。
8.4.6 雙重鎖校驗(線程安全)


雙重鎖的方式是方法級鎖的優化,減少了獲取實例的耗時。同時,這種方式也滿足了懶漢模式。
8.4.7 CAS“AtomicReference”(線程安全)

Java 并發庫提供了很多原子類支持并發訪問的數據安全性,如:AtomicInteger、AtomicBoolean、AtomicLong 和 AtomicReference。AtomicReference<V> 可以封裝引用一個V實例,上面支持并發訪問的單例模式就是利用了這種特性。使用CAS的好處是不需要使用傳統的加鎖方式,而是依賴CAS的忙等算法、底層硬件的實現保證線程安全。相對于其他鎖的實現,沒有線程的切換和阻塞也就沒有了額外的開銷,并且可以支持較大的并發。當然,CAS也有一個缺點就是忙等,如果一直沒有獲取到,會陷于死循環。
8.4.8 Effective Java作者推薦的枚舉單例(線程安全)

Joshua J.Bloch是美國著名的程序員,他為Java平臺設計并實現了許多功能,曾擔任Google公司的首席Java架構師,是Effective Java的作者。
Joshua J.Bloch推薦使用枚舉的方式解決單例模式,此種方式可能是平時最少用到的。這種方式解決了最主要的線程安全、自由串行化和單一實例問題。調用方式如下:

這種寫法雖然在功能上與共有域的方法接近,但是它更簡潔。即使在面對復雜的串行化或反射攻擊時,也無償地提供了串行化機制,絕對防止對此實例化。雖然這種方式還沒有被廣泛采用,但是單元素的枚舉類型已經成為實現Singleton的最佳方法。
同時,我們也要知道在存在繼承的場景下,此種方式是不可用的。
- C語言程序設計基礎與實驗指導
- 華為HMS生態與應用開發實戰
- Production Ready OpenStack:Recipes for Successful Environments
- Java持續交付
- ASP.NET 3.5程序設計與項目實踐
- Mastering Linux Network Administration
- 焊接機器人系統操作、編程與維護
- Python編程從0到1(視頻教學版)
- jQuery Mobile移動應用開發實戰(第3版)
- C語言程序設計
- Spring Boot+MVC實戰指南
- Angular應用程序開發指南
- Android Game Programming by Example
- C語言從入門到精通
- Android應用程序設計