設計模式(一)單例模式
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對象在不同編譯單元中的初始化順序是未定義的,兩個單例交互就可能出現問題。
設計模式(一)單例模式