singleton是二十三個設計模式中比較重要也比較經常使用的模式。但是這個模式雖然簡單,實現起來也會有一些小坑,讓我們一起來看看吧!
首先我們看看這個設計模式的uml類圖。
很清晰的可以看到,有三點是需要我們在實現這個模式的時候注意的地方。
其中,私有化構造器是防止外部使用者建立新的例項而靜態方法用於返回全域性唯一的靜態例項供使用者使用。原理清楚了,接下來我們看看一些典型的實現方式和其中的暗坑。
最簡單的實現方法自然就是按照uml類圖直接寫乙個類,我們看看**。
class program
}class singleton
public static singleton instance
www.cppcns.com return _instance;}}
public void dumbmethod()
}這段**忠實的實現了uml類圖裡面的一切,檢視輸出結果,
證實了singleton確實起了作用,多次呼叫僅僅產生了乙個例項,似乎這麼寫就可以實現這個模式了。但是,真的會那麼簡單嗎?
現在我們給剛剛的例子加點調料,假設多個對例項的呼叫,並不是簡單的,彬彬有禮的順序關係,二是以多執行緒的方式呼叫,那麼剛剛那種實現方法,還能從容應對嗎?讓我們試試。把main函式裡面的呼叫改成這樣。
static void main(string args));}
task.waitall(tasks);
console程式設計客棧.readline();
}通過factory創造出1萬個task,幾乎同時去請求這個單例,看看輸出。
咦,我們剛剛寫的singleton模式失效了,這個類被創造了5次(這段**執行多次,這個數字不一定相同),一定是多執行緒搞的鬼,我們剛剛寫的**沒有辦法應對多執行緒,換句話說,是非執行緒安全的(thread-safe),那有沒有辦法來攻克這個難關呢?
lock版本
提到執行緒安全,很多同學第一反應就是用lock,不錯,lock是個可行的辦法,讓我們試試。新增乙個引用型別的物件作為lock物件,修改**如下(什麼?你問我為什必須是引用型別的物件而不能是值型別的物件?因為lock的時候,如果物件是值型別,那麼lock僅僅鎖住了它的乙個副本,另外乙個執行緒可以暢通無阻的再次lock,這樣lock就失去了阻塞執行緒的意義)
private static object _syncobj = new object();
public static singleton instance
return _instance;
} }}
執行一下,輸出
只有乙個例項建立,證明lock起作用了,這個模式可行!不過有些不喜歡用lock的同學可能要問,還有沒有其他辦法呢?答案是有的。
靜態構造器版本
回想一下,c#中的類靜態構造器,只會在這個類第一次被使用的時候呼叫一次,天然的執行緒安全,那我們試試不用lock使用類靜態構造器?修改singleton類如下:
class singleton
static singleton()
//private static object _syncobj = new object();
public static singleton instance
}public void dumbmethod()
}去掉了lock,新增了乙個類靜態構造器,試一試。
完美!對於不喜歡用lock(在這個例子中,例項只會建立一次但是之後的所有執行緒都要先排隊lock再進入critical code進行檢查,效率比較低下)的同學,類靜態egywrwmtqn構造器提供了一種很好的選擇。
不過俗話說,人心苦不足 , 我們總是追求卓越。這個版本比lock版本似乎更好一點,那還有沒有更好的版本呢?有的。
lazy版本
從net 4.0開始,c#開始支援延遲初始化,通過lazy關鍵字,我們可以宣告某個物件為僅僅當第一次使用的時候,再初始化,如果一直沒有呼叫,那就不初始化,省去了一部分不必要的開銷,提公升了效率。如果你不熟悉lazy或者想更多了解它,請參考。我們今天關注的重點在於,lazy也是天生執行緒安全的,所以我們嘗試用它來實現singleton模式?修改**如下:
class singleton
public static singleton instance
}public void dumbmethod()
}輸出結果中可以看到,我們達到了想要的效果:
在上面的**中,私有變數_instance現在是被宣告為延遲初始化,這樣不但天然實現了執行緒安全,同時在沒有呼叫instance靜態方法的時候(也即沒有呼叫_instance.value),初始化不會發生,這樣就提高了效率。
singleton模式很常見,實現起來也很簡單,只是要小心執行緒安全。以上三種方法都可以實現執行緒安全的singleton模式。如果net 版本在4.0之上,建議使用lazy版本,畢竟對比lock版本,lazy版本可以免去實現手動lock之苦,對比static版本,又有延遲初始化的效能優勢,何樂而不為呢?
C 設計模式之Singleton
一 功能保證乙個類僅有乙個例項。二 結構圖 三 優缺點 singleton模式是做為 全域性變數 的替代品出現的。所以它具有全域性變數的特點 全域性可見 貫穿應用程式的整個生命期,它也具有全域性變數不具備的性質 同型別的物件例項只可能有乙個。四 實現 教科書上的singleton定義如下 class...
C 設計模式之Singleton
一 功能 保證乙個類僅有乙個例項。二 結構圖 三 優缺點 singleton模式是做為 全域性變數 的替代品出現的。所以它具有全域性變數的特點 全域性可見 貫穿應用程式的整個生命期,它也具有全域性變數不具備的性質 同型別的物件例項只可能有乙個。四 實現 教科書上的singleton定義如下 clas...
C 設計模式之Singleton
名稱 singleton 結構 意圖 保證乙個類僅有乙個例項,並提供乙個訪問它的全域性訪問點。適用性 當類只能有乙個例項而且客戶可以從乙個眾所周知的訪問點訪問它時。當這個唯一例項應該是通過子類化可擴充套件的,並且客戶應該無需更改 就能使用乙個擴充套件的例項時。示例 singleton namespa...