一、單例模式的c#實作:
(1)使用double-checked locking的方式:


這種實作方式對多線程來說是安全的,同時線程不是每次都加鎖,隻有判斷對象執行個體沒有被建立時它才加鎖。注意volatile的使用,隻有加了volatile修飾,才能保證在多線程環境下隻有一個執行個體。
因為使用了鎖,沒有下面的方式高效。


如果多個線程同時調用getinstance(),會産生多個singleton對象,但是interlocked.compareexchange()會保證隻有一個引用指派給instance,沒有引用到的對象會被垃圾回收。
(2)使用靜态成員初始化方式(thread-safe without using locks)


由于instance是static的,保證在appdomain隻有一個執行個體。
初始化的線程安全性是由.net保證的。
手動加上一個static的constructor,以讓.net對它進行延遲加載,但并不是完全延遲初始化,當該單例有其他static成員被使用時,該instance就被建立,而不是該instance被使用時才被建立。
(3)推薦方式:使用内部一個instance的holder來“持有”單例


這種實作方式不需要加鎖(without using locks)。
這種方式是完全延遲初始化(fully lazy instantiation),該instance隻有被使用時才被建立。
(4)最簡單有效方式:


這種方式的簡單和性能良好,而且還提供檢查是否已經建立執行個體的屬性isvaluecreated。
二、單例模式的java實作:


雙重檢驗鎖模式(double checked locking pattern), 是一種使用同步塊加鎖的方法。程式員稱其為雙重檢查鎖,因為會有兩次檢查 instance == null ,一次是在同步塊外,一次是在同步塊内。 為什麼在同步塊内還要再檢驗一次?因為可能會有多個線程一起進入同步塊外的 if, 如果在同步塊内不進行二次檢驗的話就會生成多個執行個體了。
注意:這裡的volatile修飾是必不可少的,當一個變量被volatile修飾後, 它将具備兩種特性:
1. 線程可見性:當一個線程修改了被volatile修飾的變量後,無論是否加鎖,其它線程都可以立即看到最新的修改,而普通變量卻做不到這點;
2. 禁止指令重排序優化:普通的變量僅僅保證在該方法的執行過程中所有依賴指派結果的地方都能擷取正确的結果,而不能保證變量指派操作的順序與程式代碼的執行順序一緻。
(2)使用eager initialization的方式:


(3)推薦實作:initialization on demand holder idiom


這種寫法仍然使用jvm本身機制保證了線程安全問題,由于 singletonholder 是私有的,除了getinstance()之外沒有辦法通路它,是以它是lazy initialized的,同時讀取執行個體的時候不會進行同步,沒有性能缺陷,也不依賴 jdk 版本。
(4)最簡單實作:使用一個enum來實作,線程安全性由jvm保證。


可以通過singletonenum.instance來通路執行個體,這比調用getinstance()方法簡單多了。 建立枚舉預設就是線程安全的,是以不需要擔心double checked locking, 而且還能防止反序列化導緻重新建立新的對象。
參考:
http://en.wikipedia.org/wiki/singleton_pattern
http://www.yoda.arachsys.com/csharp/singleton.html
http://www.cnblogs.com/rush/archive/2011/10/30/2229565.html
http://javarevisited.blogspot.gr/2012/07/why-enum-singleton-are-better-in-java.html
http://javarevisited.blogspot.sg/2011/03/10-interview-questions-on-singleton.html
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。
http://www.cnblogs.com/luxiaoxun/p/3841223.html