官术网_书友最值得收藏!

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的最佳方法。

同時,我們也要知道在存在繼承的場景下,此種方式是不可用的。

主站蜘蛛池模板: 盐源县| 贡觉县| 安顺市| 江口县| 高碑店市| 贵阳市| 承德市| 高密市| 小金县| 银川市| 东丽区| 横峰县| 饶平县| 蒙自县| 江华| 肇州县| 庐江县| 富源县| 独山县| 叙永县| 彭山县| 平果县| 蕉岭县| 江门市| 宜阳县| 新建县| 吴桥县| 鄯善县| 宝兴县| 甘南县| 宁晋县| 商南县| 莱州市| 渭源县| 普安县| 电白县| 龙井市| 政和县| 华蓥市| 宁武县| 宜宾县|