文章目錄
- 第一種 (classic)
- 第二種 (use "synchronize" keyword)
- 第三種 (eagerly create )
- 第四種 (雙檢鎖)
- 第五種(lazy initialization holder class)
- 第六種(Enum Singleton)
Time:3 hours
從形式上來看,Singleton Pattern是所有模式中最簡單的一種,但是細究起來並不像想象中那麼簡單。
Singleton的實現有多種方式(見下表及文後所附程式碼範例)。最基本的是第一種實現,這種實現最大的問題就是不支援多線程。《Head First Design Pattern》第五章列舉了三種支援多線程的單例模式實現方式(表中第二、三、四種),這三種實現方式在效能上有所差異。
對於第四種雙檢鎖(DCL)方式,文中特別註明“在Java1.4及更早版本中,許多JVM對volatile關鍵詞的實現,會導致雙重檢查加鎖的實效”;博文[3][4]中對這個問題進行了說明:可能出現instance被賦值,但instance指向的對象尚未初始化完成的情況,此時其他線程若讀取instance,就會有問題。[4]中的原話如下:
“The problem with DCL is that code of fetching reference to constructed Singleton object does not require synchronization.
Lets say that thread ‘a’ has entered synchronized block, made the instance not null but hasn’t executed the constructor yet. At this stage thread ‘b’ preempts thread ‘a’. Thread ‘b’ checks if the instance is not null, and since its not, it returns reference to a partially constructed Singleton object.”
從JDK 1.5開始,這個問題已經被解決,DCL方式可正常運行。
《Effective Java》中作者又提及另兩種實現方式:
第五種 Class holder lazy initialization (見Item 71): 能達到DCL方式一樣的功效,但實現更簡單。Joshua沒有明說,但是從書中他的話來看,對靜態域使用延遲初始化(Singleton模式中正是這種情況),應使用這種方式而不是DCL方式。由於這種方式只適用於靜態域的情況,DCL方式可在執行個體域需要延遲初始化時使用。
第六種 Enum singleon (見Item 3): Joshua認為雖然這種方式還沒有被廣泛採用,但這是實現Singleton的最佳方法(更簡潔,自動支援序列化機制,絕對防止多次執行個體化)。
在網上尋找”Class holder lazy initialization ”時,發現已經有人總結過Singleton的這些實現方式[4],寫的很清楚(有點小問題:該文介紹DCL方式時,指出了這種方式存在的問題,但未說明JDK1.5開始這個問題已經被解決)。綜合這些資料,列了下面的一覽表:
|
特徵詞 |
JDK版本要求 |
是否Lazy Initialization |
是否多安全執行緒 |
實現難度 |
說明 |
| 第一種 |
classic |
|
是 |
否 |
易 |
不要求安全執行緒 |
| 第二種 |
use "synchronize" keyword |
|
是 |
是 |
易 |
getInstance()的效能對應用程式不是很關鍵(比如該方法使用不太頻繁) |
| 第三種 |
eagerly create |
|
否 |
是 |
易 |
建立該執行個體負擔不太繁重; 該執行個體被用到的可能性較大 |
| 第四種 |
雙檢鎖 (double-checked locking) |
since 1.5 |
是 |
是 |
較複雜 |
getInstance()的效能對應用程式很關鍵; |
| 第五種 |
Class holder lazy initialization |
|
是 |
是 |
一般 |
|
| 第六種 |
Enum singleton |
since 1.5 |
否 |
是 |
易 |
自動支援序列化;不能通過reflection attack來調用私人構造方法 |
(說明:由於時間關係,博主未對本文的內容進行編程驗證,相關結論根據閱讀的理解整理而來,如有錯誤歡迎指正)
References
[1] Eric Freeman, etc. Head First Design Pattern.
[2] Joshua Bloch. Effective Java. 2nd.
[3] 西坪. Java中的Volatile關鍵字. 2010-12-13. url
[4] InitBinder. Singleton Pattern and Problem With Double Checked Locking. 2008-09-06. url
附各種實現方式的程式碼範例第一種 (classic)
第二種 (use "synchronize" keyword)
第三種 (eagerly create )
第四種 (雙檢鎖)
第五種(lazy initialization holder class)
第六種(Enum Singleton)