1. 程式人生 > >單例模式淺談二

單例模式淺談二

class CSingleton /* 懶漢式 */
{ 
public:
    static CSingleton * GetInstance() // 寫法是在getInstance中new instance然後返回
    {       
        if(m_pInstance == NULL) //判斷是否第一次呼叫
            m_pInstance = new CSingleton;
        return m_pInstance;
    }
        void RelaseInstance()
        {
            delete this;
        }
private:
        CSingleton() //建構函式是私有的
        {
        }
        CSingleton(const CSingleton& that)//拷貝建構函式也應是私有的
        {
         
        }
        ~CSingleton()
        {
            m_pInstance = NULL;
        }
        static CSingleton *m_pInstance;         
};

單例模式,可以說設計模式中最常應用的一種模式了,據說也是面試官最喜歡的題目。但是如果沒有學過設計模式的人,可能不會想到要去應用單例模式,面對單例模式適用的情況,可能會優先考慮使用全域性或者靜態變數的方式,這樣比較簡單,也是沒學過設計模式的人所能想到的最簡單的方式了。

一般情況下,我們建立的一些類是屬於工具性質的,基本不用儲存太多的跟自身有關的資料,在這種情況下,每次都去new一個物件,即增加了開銷,也使得程式碼更加臃腫。其實,我們只需要一個例項物件就可以。如果採用全域性或者靜態變數的方式,會影響封裝性,難以保證別的程式碼不會對全域性變數造成影響。

考慮到這些需要,我們將預設的建構函式宣告為私有的,這樣就不會被外部所new了,甚至可以將解構函式也宣告為私有的,這樣就只有自己能夠刪除自己了。在Java和C#,QT這樣純的面向物件的語言中,單例模式非常好實現,直接就可以在靜態區初始化instance,然後通過getInstance返回,這種就被稱為餓漢式單例類。也有些寫法是在getInstance中new instance然後返回,這種就被稱為懶漢式單例類,但這涉及到第一次getInstance的一個判斷問題。

下面的程式碼只是表示一下,跟具體哪種語言沒有關係。

單執行緒中:

1

2

3

4

5

6

7

Singleton* getInstance()

{

    if (instance == NULL)

        instance = new Singleton();

 

    return instance;

}

 

這樣就可以了,保證只取得了一個例項。但是在多執行緒的環境下卻不行了,因為很可能兩個執行緒同時執行到if (instance == NULL)這一句,導致可能會產生兩個例項。於是就要在程式碼中加鎖。

/*
多執行緒同步,一旦有個一個執行緒搶到鎖之後,(每個執行緒搶到的機會都是相等,當然也可以排程),其他執行緒就會
阻塞在門外**/
Singleton* getInstance()
{
    lock();  //上鎖
    if (instance == NULL)
    {
       instance = new Singleton();
    }
    unlock();//解鎖
 
    return instance;
}

但這樣寫的話,會稍稍映像效能,因為每次判斷是否為空都需要被鎖定,如果有很多執行緒的話,就會造成大量執行緒的阻塞。再次資源浪費,於是大神們又想出了雙重鎖定。

/*
這樣就避免大量執行緒阻塞造成的資源浪費,頂多有幾個執行緒同時開始創造一個單例時,機率很小
*/
Singleton* getInstance()
{
    if (instance == NULL)
    {
	    lock();
    	if (instance == NULL)
    	{
       		instance = new Singleton();
    	}
    	unlock();
    }
 
    return instance;
}

這樣只夠極低的機率下,通過越過了if (instance == NULL)的執行緒才會有進入鎖定臨界區的可能性,這種機率還是比較低的,不會阻塞太多的執行緒,但為了防止一個執行緒進入臨界區建立例項,另外的執行緒也進去臨界區建立例項,又加上了一道防禦if (instance == NULL),這樣就確保不會重複建立了。

image_thumb[3]

 

常用的場景

單例模式常常與工廠模式結合使用,因為工廠只需要建立產品例項就可以了,在多執行緒的環境下也不會造成任何的衝突,因此只需要一個工廠例項就可以了。

 

優點

1.減少了時間和空間的開銷(new例項的開銷)。

2.提高了封裝性,使得外部不易改動例項。

 

缺點

1.懶漢式是以時間換空間的方式。

2.餓漢式是以空間換時間的方式。

此博文轉載處:https://blog.csdn.net/kaida1234/article/details/79806943