單例模式加鎖與不加鎖例項C++
阿新 • • 發佈:2018-12-27
1 教科書裡的單例模式
我們都很清楚一個簡單的單例模式該怎樣去實現:建構函式宣告為private或protect防止被外部函式例項化,內部儲存一個private static的類指標儲存唯一的例項,例項的動作由一個public的類方法代勞,該方法也返回單例類唯一的例項。
上程式碼:
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class
singleton
{
protected :
singleton(){}
private :
static
singleton* p;
public :
static
singleton* instance(); };
singleton* singleton::p = NULL;
singleton* singleton::instance()
{
if
(p == NULL)
p =
new singleton();
return
p;
}
|
這是一個很棒的實現,簡單易懂。但這是一個完美的實現嗎?不!該方法是執行緒不安全的,考慮兩個執行緒同時首次呼叫instance方法且同時檢測到p是NULL值,則兩個執行緒會同時構造一個例項給p,這是嚴重的錯誤!同時,這也不是單例的唯一實現!
2 懶漢與餓漢
單例大約有兩種實現方法:懶漢與餓漢。
-
- 懶漢:故名思義,不到萬不得已就不會去例項化類,也就是說在第一次用到類例項的時候才會去例項化,所以上邊的經典方法被歸為懶漢實現;
- 餓漢:餓了肯定要飢不擇食。所以在單例類定義的時候就進行例項化。
特點與選擇:
-
- 由於要進行執行緒同步,所以在訪問量比較大,或者可能訪問的執行緒比較多時,採用餓漢實現,可以實現更好的效能。這是以空間換時間。
- 在訪問量較小時,採用懶漢實現。這是以時間換空間。
3 執行緒安全的懶漢實現
執行緒不安全,怎麼辦呢?最直觀的方法:加鎖。
-
方法1:加鎖的經典懶漢實現:
class singleton { protected: singleton() { pthread_mutex_init(&mutex); } private: static singleton* p;public: static pthread_mutex_t mutex; static singleton* initance(); }; pthread_mutex_t singleton::mutex; singleton* singleton::p = NULL; singleton* singleton::initance() { if (p == NULL) { pthread_mutex_lock(&mutex); if (p == NULL) p = new singleton(); pthread_mutex_unlock(&mutex); } return p; }
-
方法2:內部靜態變數的懶漢實現
此方法也很容易實現,在instance函式裡定義一個靜態的例項,也可以保證擁有唯一例項,在返回時只需要返回其指標就可以了。推薦這種實現方法,真得非常簡單。
class singleton { protected: singleton() { pthread_mutex_init(&mutex); } public: static pthread_mutex_t mutex; static singleton* initance(); int a; }; pthread_mutex_t singleton::mutex; singleton* singleton::initance() { pthread_mutex_lock(&mutex); static singleton obj; pthread_mutex_unlock(&mutex); return &obj; }
4 餓漢實現
為什麼我不講“執行緒安全的餓漢實現”?因為餓漢實現本來就是執行緒安全的,不用加鎖。為啥?自己想!
?1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class
singleton
{
protected :
singleton()
{}
private :
static
singleton* p;
public :
static
singleton* initance();
};
singleton* singleton::p =
new singleton;
singleton* singleton::initance()
{
return
p;
}
|
是不是特別簡單呢?
以空間換時間,你說簡單不簡單?
面試的時候,執行緒安全的單例模式怎麼寫?肯定怎麼簡單怎麼寫呀!餓漢模式反而最懶[正經臉]!