1. 程式人生 > >設計模式(一)單例模式

設計模式(一)單例模式

分享 公有 交互 線程 加鎖 解決 操作 編譯 進入

1.單例模式(Singleton):由於某種需要,要保證一個類在程序的生命周期中只有一個實例,並提供一個該實例的全局訪問方法。

2.單例模式(Singleton)結構圖:

技術分享圖片

Singleton類,定義了一個GetInstance操作,允許客戶訪問他的唯一實例,

GetInstance是一個靜態方法,主要負責創建自己的唯一實例

3.特點:

(1)一個類只能有一個實例

(2)該類可以自行創建這個實例

(3)該類能向整個系統返回這個實例

4.單例模式一般包含三個要素:

(1)私有的靜態的實例對象 private static instance

(2)私有的構造函數 (保證在該類外部無法通過new方法創建實例對象) private Singleton(){}

(3)公有的靜態的訪問該實例的方法 public static Singleton GetInstance(){}

5.單例模式的實現

(1)懶漢式(在使用時才實例化)

 1 class Singleton  
 2 {  
 3 public:  
 4     static Singleton &GetInstance()//最好返回引用,防止用戶不小心刪除指針  
 5     {  
 6         if(instance == NULL)  
7 instance = new Singleton(); 8 return *instance; 9 } 10 private: 11 Singleton(){} 12 ~Singleton(); 13 Singleton(const Singleton&); 14 Singleton &operator = (const Singleton&);//賦值和拷貝構造要聲明為私有 15 static Singleton *instance; 16 };
17 Singleton* Singleton::instance=NULL;//靜態的數據成員必須要在類外初始化

這種實現方法沒有考慮多線程安全的情況,在多線程的程序中,如果有多個線程同時訪問Singleton類,調用GetInstance()方法,就有可能創建出多個實例。

(2)基於懶加載的線程安全(一)使用互斥鎖

 1 class Singleton  
 2 {  
 3 public:  
 4     static Singleton &GetInstance()  
 5     {  
 6         Lock();  
 7         if(instance == NULL)  
 8         {  
 9             instance = new Singleton();  
10         }  
11         Unlock();  
12         return *instance;  
13     }  
14 private:  
15     Singleton(){}  
16     ~Singleton();  
17     Singleton(const Singleton&);  
18     Singleton &operator = (const Singleton&);  
19     static Singleton *instance;  
20 };  
21 Singleton* Singleton::instance=NULL;  

Lock是用來確保當一個線程位於代碼的臨界區時,另一個線程不能進入臨界區。這樣就確保了在多線程環境下,有多個線程同時訪問時只有一個線程可以進入加鎖的部分,保證只創建一個實例。但是加鎖這個動作會不停地在用戶態和內核態之間切換,極端情況如只有單線程,這個加鎖的動作會嚴重的拖慢效率。

(3)基於懶加載的線程安全(二)

 1 class Singleton  
 2 {  
 3 public:  
 4     static Singleton &GetInstance()  
 5     {  
 6         if(instance == NULL)  
 7         {  
 8             Lock();  
 9             if(instance == NULL)  
10             {  
11                 instance = new Singleton();  
12             }  
13             Unlock();             
14         }  
15         return *instance;  
16     }  
17 private:  
18     Singleton(){}  
19     ~Singleton();  
20     Singleton(const Singleton&);  
21     Singleton &operator = (const Singleton&);  
22     static Singleton *instance;  
23 };  
24 Singleton* Singleton::instance=NULL;  

為了解決上一版本每次調用GetInstance方法是都要lock的問題,這次使用了雙重if判斷條件,先判斷實例是否存在,如果不存在,再進行加鎖。

(4)饑漢式

 1 class Singleton  
 2 {  
 3 public:  
 4     static Singleton &GetInstance()  
 5     {  
 6         return instance;  
 7     }  
 8 private:  
 9     Singleton(){}  
10     ~Singleton();  
11     Singleton(const Singleton&);  
12     Singleton &operator = (const Singleton&);  
13     static Singleton instance;  
14 };  
15 Singleton Singleton::instance;  

在饑漢模式下,單例類在定義時就創建了對象,對類進行了初始化,之後再有線程調用GetInstance()函數時,都返回的是同一個對象的指針,所以饑漢式是線程安全的。

但是函數外的static對象在不同編譯單元中的初始化順序是未定義的,兩個單例交互就可能出現問題。

設計模式(一)單例模式