單例模式,是一種常見的軟件設計模式。保證一個類只存在唯一實例。
(出現這種模式的思考,以后補充)
實現步驟:
1) 私有化構造函數,防止被實例化;
private: Singleton(){}
2) 私有化靜態實例,防止被引用;
private: Singleton* instance = NULL;
3) 提供一個靜態方法,用于創建實例。
public: Singleton* getInstance(){
? ? if(instance == NULL){
? ? ? ? instance = new Singleton();
}
return instance;
}
常用的場景
單例模式常常與工廠模式結合使用,因為工廠只需要創建產品實例就可以了,在多線程的環境下也不會造成任何的沖突,因此只需要一個工廠實例就可以了。
優點
1. 減少了時間和空間的開銷(new 實例的開銷)。
2. 提高了封裝性,使得外部不易改動實例。
缺點
1. 懶漢式是以時間換空間的方式。
2. 餓漢式是以空間換時間的方式。
單線程中:
Singleton* getInstance(){
? ? if(instance == NULL)
? ? ? ? ? ? ? ? instance = new Singleton();
return instance;
}
這樣就能保證取得一個實例。但是在多線程的環境下是不行的,因為很可能兩個線程同時運行到 if(instance == NULL)這一句,導致可能產生兩個實例。于是就要在代碼中加鎖。
Singleton* getInstance(){
? ? lock();
? ? if(instance == NULL){
? ? instance = new Singleton();
????}
? ? unlock();
? ? return instance;
}
但這樣會稍稍影響性能,因為每次判斷是否為空都需要被鎖定,如果有很多線程的話,就會造成大量線程阻塞。雙重鎖定:
Singleton* getInstance(){
if(instance == NULL){
? ? lock();
? ? if(instance == NULL){
? ? ? ? ? ? instance = new Singleton();
????}
? ? unlock();
}
return instance;
}
這樣只夠極低的幾率下,通過越過了 if(instance == NULL)的線程才會有進入鎖定臨界區的可能性,這種幾率還是比較低的,不會阻塞太多的線程,但為了防止一個線程進入臨界區創建實例,另外的線程也進去臨界區創建實例,又加上了一道防御 if(instance == NULL), 這樣就確保不會重復創建。