老生常談C++的單例模式與線程安全單例模式(懶漢/餓漢)
1 教科書里的單例模式
我們都很清楚一個(gè)簡單的單例模式該怎樣去實(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),簡單易懂。但這是一個(gè)完美的實(shí)現(xiàn)嗎?不!該方法是線程不安全的,考慮兩個(gè)線程同時(shí)首次調(diào)用instance方法且同時(shí)檢測到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)方法,真得非常簡單。
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;
}
是不是特別簡單呢?
以空間換時(shí)間,你說簡單不簡單?
面試的時(shí)候,線程安全的單例模式怎么寫?肯定怎么簡單怎么寫呀!餓漢模式反而最懶[正經(jīng)臉]!
以上就是小編為大家?guī)淼睦仙U凜++的單例模式與線程安全單例模式(懶漢/餓漢)全部內(nèi)容了,希望大家多多支持腳本之家~
相關(guān)文章
深入理解memmove()與memcpy()的區(qū)別以及實(shí)現(xiàn)方法
本篇文章是對(duì)memmove()與memcpy()的區(qū)別以及實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
Visual Studio 2022 Preview 使用 C++20 Module的詳細(xì)過程
這篇文章主要介紹了Visual Studio 2022 Preview 使用 C++20 Module的過程,本文通過項(xiàng)目分析實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2021-09-09
Qt串口通信開發(fā)之Qt串口通信模塊QSerialPort開發(fā)完整實(shí)例(串口助手開發(fā))
這篇文章主要介紹了Qt串口通信開發(fā)之Qt串口通信模塊QSerialPort開發(fā)完整實(shí)例(串口助手開發(fā)),需要的朋友可以參考下2020-03-03
C++實(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

