C++的單例模式與線程安全單例模式(懶漢/餓漢)

1 教科書裏的單例模式

  咱們都很清楚一個簡單的單例模式該怎樣去實現:構造函數聲明爲private或protect防止被外部函數實例化,內部保存一個private static的類指針保存惟一的實例,實例的動做由一個public的類方法代勞,該方法也返回單例類惟一的實例。面試

  上代碼:  安全

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 懶漢與餓漢

  單例大約有兩種實現方法:懶漢與餓漢。性能

    • 懶漢:故名思義,不到萬不得已就不會去實例化類,也就是說在第一次用到類實例的時候纔會去實例化,因此上邊的經典方法被歸爲懶漢實現;
    • 餓漢:餓了確定要飢不擇食。因此在單例類定義的時候就進行實例化。

  特色與選擇:spa

    • 因爲要進行線程同步,因此在訪問量比較大,或者可能訪問的線程比較多時,採用餓漢實現,能夠實現更好的性能。這是以空間換時間。
    • 在訪問量較小時,採用懶漢實現。這是以時間換空間。

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 餓漢實現

  爲何我不講「線程安全的餓漢實現」?由於餓漢實現原本就是線程安全的,不用加鎖。爲啥?本身想!code

class singleton
{
protected:
	singleton()
	{}
private:
	static singleton* p;
public:
	static singleton* initance();
};
singleton* singleton::p = new singleton;
singleton* singleton::initance()
{
	return p;
}

  是否是特別簡單呢?blog

  以空間換時間,你說簡單不簡單?同步

  面試的時候,線程安全的單例模式怎麼寫?確定怎麼簡單怎麼寫呀!餓漢模式反而最懶[正經臉]! 

相關文章
相關標籤/搜索