1、單例模式:
單例模式:用來創建獨一無二的,只能夠有一個實例的對象。 單例模式的結構是設計模式中最簡單的,但是想要完全實現一個線程安全的單例模式還是有很多陷阱的。
2、應用場景:
共享數據或者共享訪問點;
創建一個對象需要消耗的資源過多,如訪問IO和數據庫等資源;
需要定義大量的靜態常量和靜態方法(工具類)
單例模式的應用場景:有一些對象其實只需要一個,比如:windows Task Manager (任務管理器)、windows 回收站、線程池、緩存、對話框、處理偏好設置和注冊表的對象、日志對象、充當打印機、顯卡等設備的驅動程序對象。這些對象只能夠擁有一個實例,如果創建出了多個實例,就會導致一些程序的問題。程序的行為異常,資源使用的過量,或者導致不一致的結果。常用來管理共享的資源,比如數據庫的連接或者線程池。
3、優缺點:
優點:一個實例,減少內存開銷;減少系統開銷;避免對一個資源的多重占用;設置全局訪問點,優化和貢獻資源。
缺點:沒有借口,擴展性差;不利於測試;與單一職責原則有沖突,單例模式把“要單例”和業務邏輯融合在一個類中。
4、實現
1、經典實現(線程不安全)
1 class Singleton 2 { 3 public: 4 static Singleton* getInstance(); 5 protected: 6 Singleton(){} 7 private: 8 static Singleton *p; 9 }; 10 11 Singleton* Singleton::p = NULL; 12 Singleton* Singleton::getInstance() 13 { 14 if (NULL == p) 15 p = new Singleton(); 16 return p; 17 }
1 1、當兩個線程運行至if(instance==NULL)時,可能產生線程安全問題。 2 3 改進:在用到的時候在初始化,這樣程序效率比較高,但是有一個另外比較好的方法可以采用是提前初始化,將Instance設置為static之后直接初始化為Singleton對象,每次只需要執行返回操作即可。 4 5 class Singleton { 6 public: 7 static Singleton* getInstance(); 8 9 protected: 10 11 Singleton(); 12 13 private: 14 static Singleton *instance; 15 }; 16 17 //對單例直接進行初始化,而不再方法Instance中進行判斷。 18 19 Singleton* Singleton::instance = new Singleton; 20 21 Singleton* Singleton::getInstance() 22 23 { 24 25 return instance; 26 27 } 28 這樣的話同樣會導致問題,就是如果單例本來資源比較多,但是不需要創建那么早,就會消耗資源~ 29 30 2、另外一種提升因為同步導致的性能變差的方法稱為“雙重檢驗加鎖”。方法如下: 31 32 class Singleton { 33 public: 34 static Singleton* getInstance(); 35 protected: 36 Singleton(); 37 private: 38 static Singleton* instance; 39 } 40 41 Singleton *Singleton::instance = NULL; 42 Singleton* Singleton::getInstance() { 43 //check 之前進行臨界區加鎖操作 44 //雙重檢驗加鎖 45 if(_instance == NULL ) { 46 lock(); 47 if( instance == NULL) { 48 instance = new Singleton(); 49 } 50 Unlock(); 51 } 52 return _instance; 53 } 54 55 思路是只有在第一次創建的時候進行加鎖,當instance不為空的時候就不需要進行加鎖的操作,這樣就可以提升性能~
2、懶漢模式與餓漢模式
懶漢:故名思義,不到萬不得已就不會去實例化類,也就是說在第一次用到類實例的時候才會去實例化,所以上邊的經典方法被歸為懶漢實現;
餓漢:餓了肯定要飢不擇食。所以在單例類定義的時候就進行實例化。
特點與選擇
區別:由於要進行線程同步,所以在訪問量比較大,或者可能訪問的線程比較多時,采用餓漢實現,可以實現更好的性能。這是以空間換時間。在訪問量較小時,采用懶漢實現。這是以時間換空間。
1 1.加鎖實現線程安全的懶漢模式 2 3 class Singleton 4 { 5 public: 6 static pthread_mutex_t mutex; 7 static Singleton* getInstance(); 8 protected: 9 Singleton() 10 { 11 pthread_mutex_init(&mutex); 12 } 13 private: 14 static Singleton* p; 15 }; 16 17 pthread_mutex_t Singleton::mutex; 18 Singleton* Singleton::p = NULL; 19 Singleton* Singleton::getInstance() 20 { 21 if (NULL == p) 22 { 23 pthread_mutex_lock(&mutex); 24 if (NULL == p) 25 p = new Singleton(); 26 pthread_mutex_unlock(&mutex); 27 } 28 return p; 29 } 30 31 2.內部靜態變量實現懶漢模式 32 33 class Singleton 34 { 35 public: 36 static pthread_mutex_t mutex; 37 static Singleton* getInstance(); 38 protected: 39 Singleton() 40 { 41 pthread_mutex_init(&mutex); 42 } 43 }; 44 45 pthread_mutex_t Singleton::mutex; 46 Singleton* Singleton::getInstance() 47 { 48 pthread_mutex_lock(&mutex); 49 static singleton obj; 50 pthread_mutex_unlock(&mutex); 51 return &obj; 52 }
1 餓漢模式 2 3 class Singleton 4 { 5 public: 6 static Singleton* getInstance(); 7 protected: 8 Singleton(){} 9 private: 10 static Singleton* p; 11 }; 12 13 Singleton* Singleton::p = new Singleton; 14 Singleton* Singleton::getInstance() 15 { 16 return p; 17 }