c 單例模式

2021-06-22 09:10:48 字數 2881 閱讀 5498

設計模式(

design pattern

)是一套被反覆使用、多數人知曉的、經過分類編目的、**設計經驗的

總結。使用設計模式是為了可重用**、讓**更容易被他人

理解、保證**

可靠性。而設計模式中最常見的大概就是單例模式了,關於單例模式的文章有很多,有的已經講得非常好了。本文試圖從3w的角度來說明單例模式。

單例模式的存在是理所當然的。比如中國有很多皇帝,但是同一時期只能有乙個皇帝,那個時期的百姓一談皇帝就知道是說的哪乙個皇帝。又比如你是乙個富翁,你有很多汽車,但是某一時刻你只能從車庫裡拿出一輛車坐在裡面,不可能坐在兩輛車裡,除非你有分身術。再比如畫畫程式的工具箱,登錄檔編輯器,列印程式等。用專業的話來說,就是某乙個時刻,乙個類只能有乙個例項化的物件。

單例模式的定義如下:「ensure a class has only one instance,and provide a global point of access to it.」(確保乙個類只有乙個例項,並提供乙個訪問它的全域性訪問點)

關於這句話,有以下幾點需要說明:

(1)單例類有且只有乙個例項。說到這裡,我們需要提一下靜態類了。靜態類是不能例項化的(任何地方都不能),它只有靜態的屬性和方法。靜態類主要用於共享和提供通用的功能,例如提供數學計算的math類。單例模式中的類不能在類之外例項化,但是可以在類裡面例項化。這也正是它為什麼能夠提供乙個例項的原因。

(2)既然不允許外部new,那麼需要將建構函式私有化。

(3)外部要能訪問這個例項化的物件。很簡單,我們只需要提供乙個靜態方法,供外部訪問該例項即可。

然後我再來看類圖就十分輕鬆了:

通過單例模式的定義及分析,寫出單例模式的類就很容易了。

public sealed class singleton//將建構函式私有化,防止外部建立物件

public static singleton getinstance()//提供乙個訪問點

}

我們來分析這段**,sealed關鍵字是防止類派生,因為派生也可能產生出新的例項。readonly關鍵字表明字段只能作為宣告的一部分或者建構函式中出現。當整個類被載入的時候,就會自行初始化 singleton 這個靜態唯讀變數。也就是說,不管我們用沒用到,它就已經開始存在了,而不是我們需要的時候才去例項化乙個物件出來。這種方式稱之為:餓漢單例模式。

如果我們再懶一點,想在需要它的時候再例項化呢?這個不難實現,只需要稍微做一下改動就好了:

public class singleton//將建構函式私有化,防止外部建立物件

public static singleton getinstance()//提供乙個訪問點

return singleton;}}

這個在需要時才建立例項的方式稱之為:懶漢單例模式。似乎問題解決了,但是這個是執行緒不安全的。在單執行緒下,這個沒有任何問題,在多執行緒下面就可能會出現多個例項!原因就在於singleton==null的判斷。例如執行緒a執行到singleton==null,發現沒有例項,於是開始建立新例項,在還沒建立完成的時候,執行緒b恰好也執行到singleton==null,也發現沒有例項,於是也開始建立新例項,這樣就會出現兩個例項!這能叫單例模式嗎?顯然不能!

怎麼解決呢?其實,我們可以通過給正在建立例項的執行緒加上一把鎖,這樣別的執行緒就無法建立新的例項了。關於lock的使用可以參考msdn,位址如下:

正確的餓漢單例模式:

public class singleton 

public static singleton getinstance()

} }

return singleton; } }

關於這段**,有以下幾點需要說明:

1.類中有定義了乙個私有靜態的唯讀物件  syncobject。

lock 關鍵字的引數必須為基於引用型別的物件,該物件用來定義鎖的範圍,singleton 最初為 null ,是無法實現加鎖的,所以必須要乙個例項化的物件即 syncobject 來定義加鎖的範圍。

2.在 getinstance()中,在 if 語句中使用兩次判斷 singleton == null ,這叫做雙重檢查鎖定。

先解釋第二個singleton == null 的必要性,它是為了防止出現多個例項而設定的。假設執行緒a順利到達第二個singleton == null,發現沒有例項,於是乎開始建立例項。建立例項的時候執行緒b通過第乙個singleton == null的判斷,順利到達lock,發現被鎖住了,於是b被阻塞。當a建立例項完成後,解鎖,此時b阻塞解除順利進入,如果沒有第二個singleton == null的判斷,那麼b就要開始建立例項了,那麼就會同時存在兩個例項!所以正確的做法是,執行緒b再次判斷singleton == null,發現有例項了,於是直接返回該例項即可。

再來解釋第乙個singleton == null。沒有第乙個singleton == null的判斷,程式其實是正常的,通過分析就可以知道。而問題在於,如果沒有這個「多餘」的判斷,在多執行緒下,每個執行緒到這裡都會執行加鎖的操作,這是不必要的,而且是耗費效能的。

餓漢單例和懶漢單例的使用,要根據實際情況。不過引用《大話設計模式》中的一句話:「從c#語言角度來講,餓漢式的單例類已經足夠滿足我們的需求了。」

namespace 單例模式

public static singleton getinstance()

public static void declare()

}class program}}

2《設計模式之禪》

3.《head first 設計模式》

3.5.

6.7.

8.

C 單例模式

include using namespace std 單例類的c 實現 class singleton 構造方法實現 singleton singleton void singleton setvar int var main int main int argc,char argv return ...

C 單例模式

實現方式一 include template typename t class singleton boost noncopyable static void init private static pthread once t ponce statict value template typena...

C 單例模式

效率有點低,但是還算安全的單例模式,靜態成員實現方式 class singleton public static singleton getinstance singleton singleton getinstance unlock return m instance 內部靜態例項的懶漢模式,c ...