1. 程式人生 > 實用技巧 >(C#程式碼演示)常用的兩種單例模式--餓漢式和懶漢式

(C#程式碼演示)常用的兩種單例模式--餓漢式和懶漢式

一.餓漢式

在程式開始時,該類就建立了例項了,但可能在執行時沒有呼叫,造成不必要的消耗

程式碼:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 
 5 namespace 設計模式
 6 {
 7     class 單例Singleton1
 8     {
 9         private static 單例Singleton1 R = new 單例Singleton1(); 
10         private 單例Singleton1()
11         { }
12 
13         public static 單例Singleton1 Return單例Singleton例項()
14         {
15             return R;
16         }
17     }
18 }

二.懶漢式

只有在呼叫Return單例Singleton例項()方法時才會例項化該類,解決了可能的發生效能消耗問題,但是在多執行緒測試時出現了問題------多執行緒不安全,可以看到控制檯中輸出的HashCode一開始時不同的

這是由於 執行緒1執行到時,而3執行緒2執行到,由於R還是null,所有執行緒2還會執行if中的語句,造成執行緒出錯的問題

程式碼:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 using System.Threading;
 5 
 6 namespace 設計模式
 7 {
 8     class 單例Singleton2
 9     {
10         private static 單例Singleton2 R;
11         private 單例Singleton2()
12         { }
13 
14         public static 單例Singleton2 Return單例Singleton例項()
15         {
16             if (R == null)
17             {
18                 Thread.Sleep(3);//模擬程式延遲
19                 R = new 單例Singleton2();
20             }
21             return R;
22         }
23     }
24 }

多執行緒安全測試

程式碼:

 1 using System;
 2 using System.Threading;
 3 
 4 namespace 設計模式
 5 {
 6     class Program
 7     {
 8         static void Main(string[] args)
 9         {
10             for (int i = 0; i < 100; i++)
11             {
12                 Thread thread = new Thread(a);
13                 thread.Start();
14             }
15         }
16        static  void a()
17         {
18             單例Singleton2 a = 單例Singleton2.Return單例Singleton例項();
19             Console.WriteLine(a.GetHashCode());
20         }
21     }
22 }

測試結果:

輸出新執行緒中的 例項的HashCode,很顯然是不安全的

三.懶漢式 執行緒問題完善

雙重if可以減小lock()方法的使用,從而減小消耗

程式碼:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 
 5 namespace 設計模式
 6 {
 7     class 單例Singleton3
 8     {
 9         private static readonly object syncRoot = new object();   // 定義一個標識確保執行緒同步
10         private static 單例Singleton3 R;
11         private 單例Singleton3()
12         { }
13 
14         public static  單例Singleton3 Return單例Singleton例項()
15         {
16             if (R == null)//雙重檢測 減小消耗
17             {
18                 // 當第一個執行緒執行到這裡時,此時會對locker物件 "加鎖",
19                 // 當第二個執行緒執行該方法時,首先檢測到locker物件為"加鎖"狀態,該執行緒就會掛起等待第一個執行緒解鎖
20                 // lock語句執行完之後(即執行緒執行完之後)會對該物件"解鎖"
21                 lock (syncRoot)
22                 {
23                     if (R == null)//雙重檢測 減小消耗
24                     {
25                         R = new 單例Singleton3();
26                     }
27                    
28                 }
29             }
30             return R;
31         }
32     }
33 }

我們再輸出一下每個執行緒中的例項的HashCode