老生常談C++的單例模式與線程安全單例模式(懶漢/餓漢)
1 教科書里的單例模式
我們都很清楚一個(gè)簡(jiǎn)單的單例模式該怎樣去實(shí)現(xiàn):構(gòu)造函數(shù)聲明為private或protect防止被外部函數(shù)實(shí)例化,內(nèi)部保存一個(gè)private static的類指針保存唯一的實(shí)例,實(shí)例的動(dòng)作由一個(gè)public的類方法代勞,該方法也返回單例類唯一的實(shí)例。
上代碼:
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; }
這是一個(gè)很棒的實(shí)現(xiàn),簡(jiǎn)單易懂。但這是一個(gè)完美的實(shí)現(xiàn)嗎?不!該方法是線程不安全的,考慮兩個(gè)線程同時(shí)首次調(diào)用instance方法且同時(shí)檢測(cè)到p是NULL值,則兩個(gè)線程會(huì)同時(shí)構(gòu)造一個(gè)實(shí)例給p,這是嚴(yán)重的錯(cuò)誤!同時(shí),這也不是單例的唯一實(shí)現(xiàn)!
2 懶漢與餓漢
單例大約有兩種實(shí)現(xiàn)方法:懶漢與餓漢。
懶漢:故名思義,不到萬不得已就不會(huì)去實(shí)例化類,也就是說在第一次用到類實(shí)例的時(shí)候才會(huì)去實(shí)例化,所以上邊的經(jīng)典方法被歸為懶漢實(shí)現(xiàn);
餓漢:餓了肯定要饑不擇食。所以在單例類定義的時(shí)候就進(jìn)行實(shí)例化。
特點(diǎn)與選擇:
由于要進(jìn)行線程同步,所以在訪問量比較大,或者可能訪問的線程比較多時(shí),采用餓漢實(shí)現(xiàn),可以實(shí)現(xiàn)更好的性能。這是以空間換時(shí)間。
在訪問量較小時(shí),采用懶漢實(shí)現(xiàn)。這是以時(shí)間換空間。
3 線程安全的懶漢實(shí)現(xiàn)
線程不安全,怎么辦呢?最直觀的方法:加鎖。
方法1:加鎖的經(jīng)典懶漢實(shí)現(xiàn):
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:內(nèi)部靜態(tài)變量的懶漢實(shí)現(xiàn)
此方法也很容易實(shí)現(xiàn),在instance函數(shù)里定義一個(gè)靜態(tài)的實(shí)例,也可以保證擁有唯一實(shí)例,在返回時(shí)只需要返回其指針就可以了。推薦這種實(shí)現(xiàn)方法,真得非常簡(jiǎn)單。
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 餓漢實(shí)現(xiàn)
為什么我不講“線程安全的餓漢實(shí)現(xiàn)”?因?yàn)轲I漢實(shí)現(xiàn)本來就是線程安全的,不用加鎖。為啥?自己想!
class singleton { protected: singleton() {} private: static singleton* p; public: static singleton* initance(); }; singleton* singleton::p = new singleton; singleton* singleton::initance() { return p; }
是不是特別簡(jiǎn)單呢?
以空間換時(shí)間,你說簡(jiǎn)單不簡(jiǎn)單?
面試的時(shí)候,線程安全的單例模式怎么寫?肯定怎么簡(jiǎn)單怎么寫呀!餓漢模式反而最懶[正經(jīng)臉]!
以上就是小編為大家?guī)淼睦仙U凜++的單例模式與線程安全單例模式(懶漢/餓漢)全部?jī)?nèi)容了,希望大家多多支持腳本之家~
相關(guān)文章
C語言實(shí)現(xiàn)堆排序的簡(jiǎn)單實(shí)例
這篇文章主要介紹了C語言實(shí)現(xiàn)堆排序的簡(jiǎn)單實(shí)例,講述了堆排序的原理,需要的朋友可以參考下2014-07-07深入理解memmove()與memcpy()的區(qū)別以及實(shí)現(xiàn)方法
本篇文章是對(duì)memmove()與memcpy()的區(qū)別以及實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05Visual Studio 2022 Preview 使用 C++20 Module的詳細(xì)過程
這篇文章主要介紹了Visual Studio 2022 Preview 使用 C++20 Module的過程,本文通過項(xiàng)目分析實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-09-09Qt串口通信開發(fā)之Qt串口通信模塊QSerialPort開發(fā)完整實(shí)例(串口助手開發(fā))
這篇文章主要介紹了Qt串口通信開發(fā)之Qt串口通信模塊QSerialPort開發(fā)完整實(shí)例(串口助手開發(fā)),需要的朋友可以參考下2020-03-03C++實(shí)現(xiàn)校園運(yùn)動(dòng)會(huì)報(bào)名系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)校園運(yùn)動(dòng)會(huì)報(bào)名系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-10-10