https://www.cnblogs.com/qiaoconglovelife/p/5851163.html
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; } |
是不是特別簡單呢?
以空間換時間,你說簡單不簡單?
面試的時候,線程安全的單例模式怎么寫?肯定怎么簡單怎么寫呀!餓漢模式反而最懶[正經臉]!