我的web應用程序需要這種類似於數據庫連接的對象。創建起來很慢,而且很少使用,所以我只想保留它的一個實例。如果多個請求同時需要它們,它們將lock()
對象並序列化它們的訪問權限。如何創建一個IDisposable線程安全的單實例?
爲了讓事情更有趣,該對象是一個IDisposable對象,可以關閉。當然,我會避免編寫關閉它的代碼,但是......你知道......比對不起更安全,對吧?
於是,天真的辦法是實現它是這樣的:
private static DBClass _Instance;
private static object _DBLock = new object();
public DBClass GetDB()
{
if (_Instance == null)
lock (_DBLock)
if (_Instance == null)
_Instance = CreateInstance();
lock (_Instance)
if (_Instance.Disposed)
_Instance = CreateInstance();
return _Instance;
}
然後它將被使用,如:
lock (var Conn = Global.GetDB())
{
// Use Conn here.
}
這可能會工作的大部分時間,但我看到一個可以被利用的開放 - 如果兩個線程同時調用它,它們會同時獲得相同的實例,然後在另一個線程獲取lock()
之前,它仍然可以使用Dispose()
。因此 - 後來的代碼失敗。在每個使用它的地方檢查Disposed
也似乎很尷尬。實際上,lock()
看起來也很尷尬,但實例本身並不是線程安全的,所以我無能爲力。
你將如何實現這一點?
問題是,這件事返回其他對象,它持有對它的引用並對其執行操作。除非我包裝幾百個課程,否則將無法使用。 Action <>方法值得注意,但我想知道代碼中增加的混亂是否值得。我想要一個優雅的方法,但這是有點去另一種方式... – 2009-10-26 11:22:00
順便說一句 - 我在那裏使用一個鎖()。爲什麼需要易變? – 2009-10-26 11:25:20
由於* secondary *鎖定,您可能確實沒關係 - 但考慮到您涉及到兩個不同的鎖,因此我完全不清楚它真的*是*沒問題。我個人使用一個單一的鎖 - 把整個方法放在一個使用'_DBLock'的鎖定語句中。內存模型的微妙之處非常棘手。同樣,如果另一個線程在不使用鎖定的情況下使用該對象,但不能保證你會發現它並創建一個新的實例。基本上感覺這個設計爲很多微妙的錯誤開闢了空間。 – 2009-10-26 11:31:43