老生常談C++的單例模式與線(xiàn)程安全單例模式(懶漢/餓漢)
1 教科書(shū)里的單例模式
我們都很清楚一個(gè)簡(jiǎn)單的單例模式該怎樣去實(shí)現(xiàn):構(gòu)造函數(shù)聲明為private或protect防止被外部函數(shù)實(shí)例化,內(nèi)部保存一個(gè)private static的類(lèi)指針保存唯一的實(shí)例,實(shí)例的動(dòng)作由一個(gè)public的類(lèi)方法代勞,該方法也返回單例類(lèi)唯一的實(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)嗎?不!該方法是線(xiàn)程不安全的,考慮兩個(gè)線(xiàn)程同時(shí)首次調(diào)用instance方法且同時(shí)檢測(cè)到p是NULL值,則兩個(gè)線(xiàn)程會(huì)同時(shí)構(gòu)造一個(gè)實(shí)例給p,這是嚴(yán)重的錯(cuò)誤!同時(shí),這也不是單例的唯一實(shí)現(xiàn)!
2 懶漢與餓漢
單例大約有兩種實(shí)現(xiàn)方法:懶漢與餓漢。
懶漢:故名思義,不到萬(wàn)不得已就不會(huì)去實(shí)例化類(lèi),也就是說(shuō)在第一次用到類(lèi)實(shí)例的時(shí)候才會(huì)去實(shí)例化,所以上邊的經(jīng)典方法被歸為懶漢實(shí)現(xiàn);
餓漢:餓了肯定要饑不擇食。所以在單例類(lèi)定義的時(shí)候就進(jìn)行實(shí)例化。
特點(diǎn)與選擇:
由于要進(jìn)行線(xiàn)程同步,所以在訪(fǎng)問(wèn)量比較大,或者可能訪(fǎng)問(wèn)的線(xiàn)程比較多時(shí),采用餓漢實(shí)現(xiàn),可以實(shí)現(xiàn)更好的性能。這是以空間換時(shí)間。
在訪(fǎng)問(wèn)量較小時(shí),采用懶漢實(shí)現(xiàn)。這是以時(shí)間換空間。
3 線(xiàn)程安全的懶漢實(shí)現(xiàn)
線(xiàn)程不安全,怎么辦呢?最直觀(guā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)
為什么我不講“線(xiàn)程安全的餓漢實(shí)現(xiàn)”?因?yàn)轲I漢實(shí)現(xiàn)本來(lái)就是線(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í)間,你說(shuō)簡(jiǎn)單不簡(jiǎn)單?
面試的時(shí)候,線(xiàn)程安全的單例模式怎么寫(xiě)?肯定怎么簡(jiǎn)單怎么寫(xiě)呀!餓漢模式反而最懶[正經(jīng)臉]!
以上就是小編為大家?guī)?lái)的老生常談C++的單例模式與線(xiàn)程安全單例模式(懶漢/餓漢)全部?jī)?nèi)容了,希望大家多多支持腳本之家~
相關(guān)文章
C語(yǔ)言實(shí)現(xiàn)堆排序的簡(jiǎn)單實(shí)例
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)堆排序的簡(jiǎn)單實(shí)例,講述了堆排序的原理,需要的朋友可以參考下2014-07-07C語(yǔ)言?超詳細(xì)總結(jié)講解二叉樹(shù)的概念與使用
二叉樹(shù)可以簡(jiǎn)單理解為對(duì)于一個(gè)節(jié)點(diǎn)來(lái)說(shuō),最多擁有一個(gè)上級(jí)節(jié)點(diǎn),同時(shí)最多具備左右兩個(gè)下級(jí)節(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)。本文將詳細(xì)介紹一下C++中二叉樹(shù)的概念和結(jié)構(gòu),需要的可以參考一下2022-04-04深入理解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ì)過(guò)程
這篇文章主要介紹了Visual Studio 2022 Preview 使用 C++20 Module的過(guò)程,本文通過(guò)項(xiàng)目分析實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-09-09Qt串口通信開(kāi)發(fā)之Qt串口通信模塊QSerialPort開(kāi)發(fā)完整實(shí)例(串口助手開(kāi)發(fā))
這篇文章主要介紹了Qt串口通信開(kāi)發(fā)之Qt串口通信模塊QSerialPort開(kāi)發(fā)完整實(shí)例(串口助手開(kāi)發(fā)),需要的朋友可以參考下2020-03-03C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單版三子棋
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單版三子棋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10C++實(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