設計模式 - 單例模式Singleton的8種寫法

weixin_42254177發表於2020-10-11

在這裡插入圖片描述
.
阻止別人建立第二個例項

.

總共有8種寫法

.

第1種 餓漢式

在這裡插入圖片描述
不算完美, 但是比較實用, 所以比較推薦
一般程式設計師不太會去呼叫Class.forName(), 也就不會觸發new例項

.

第2種 餓漢式 - static程式碼塊 ( 跟第一種是一個意思 )

在這裡插入圖片描述
.

第3種 Lazy Loading 懶漢式 執行緒不安全

在這裡插入圖片描述
.

第4種 懶漢式 - 在getInstance方法上加synchronized關鍵字

在這裡插入圖片描述
執行緒安全, 但是會有長期的效能問題 ( 每次呼叫getInstance方法, 都會涉及加鎖操作 )
.

第5種 懶漢式 synchronized程式碼塊 執行緒不安全

在這裡插入圖片描述
解決了初始化完成之後, 效能下降的問題, 只有在初期, 程式碼才會進入synchronized
但是仍然有可能會有多個執行緒進入synchronized同步程式碼塊, 每次進去, 都會new一個例項, 所以也是有問題的

第6種 雙重判空 + synchronized 很多人認為的完美解法

最主要的缺點就是太複雜
在這裡插入圖片描述
第一個判空是有必要的, 可以阻止很多執行緒一上來就去獲取鎖, 這樣就又退回到前一個解法了

截圖中的instance漏加了volatile, 看吧 ! ! 多複雜 ! 容易寫錯 !

.

第7種 靜態內部類方式 ( 第一種完美解法)

在這裡插入圖片描述
在內部類裡給instance直接賦值, 靜態內部類必須是private的
載入外部類的時候, 不會載入內部類, 這樣就實現了懶載入
載入指的是Class.forName, 但由於程式設計師一般不會使用Class.forName, 所以更推薦第一種寫法
JVM能保證載入一個類, 只會載入一次, 所以只會new一次

第8種 列舉enum 完美中的完美(語法層面)

java創始人之一, 在Effective Java一書中的推薦

在這裡插入圖片描述
.

為什麼要在單例模式中防止反序列化?

前面7種解法, 都可以用反射的方式, 建立出第二個例項!!!

列舉類為什麼可以防止反射?

因為列舉類沒有構造方法, 即使用反射拿到class物件, 也沒法呼叫構造方法

但是也有缺點: 寫起來彆扭, 還是用class寫起來比較順, 定義成enum總感覺寫邏輯不太舒服

.

總結

在專案中最推薦用第一種寫法, 最簡單好記, 執行緒安全
首先程式設計師一般不會去呼叫Class.forName去載入它, 所以只是看上去像餓漢, 實際上卻和懶漢差不多
另外, 程式設計師更不會去用反射故意去new第二個物件, 這種故意搞破壞不在考慮範圍之內

第六種寫法太複雜, 要記得細節點特別多, 而且也沒法阻止反射的方法
第七種寫法相對簡單, 比第一種還是有些複雜, 而且也沒法阻止反射的方法
第八種寫法在語法上是完美的, 簡單, 執行緒安全, 防止反射, 就是寫起來彆扭
.

相關文章