2009-07-30 52 views
2

在C#中,我有以下的非常詳細的語法從數據庫中提取項目的簡單列表:如何使雙重檢查的鎖定語法不再冗長?

if (malls == null) 
{ 
    lock (_lock) 
    { 
     if (malls == null) 
     { 
      using (var session = NhibernateHelper.OpenSession()) 
      { 
       malls = session.CreateCriteria<Mall>() 
        .AddOrder(Order.Asc("Name")).List<Mall>(); 

       CacheManager.Set(CACHE_KEY, malls, TimeSpan.FromMinutes(CACHE_DURATION)); 
      } 
     } 
    } 
} 

我所知道的雙重檢查鎖定的好處,我強烈支持它的使用,但它似乎非常冗長。你能推薦任何語法快捷方式或樣式可能會清理它一點?

+0

我有興趣在這種模式的可能帶來的利益。根據我的經驗,人們嚴重誤解了這種模式,並且它的含義(例如,由於內存模型的差異,它在Mono上不能可靠地工作)。我從來沒有見過它所能帶來的所有好處。 – JaredPar 2009-07-30 14:58:06

+0

有問題的方法將從數據庫中取出大約5000條記錄到內存中緩存。它將用於流量很大的ASP.NET站點,每秒鐘可能會被調用數百次到幾千次,所以我肯定希望緩存數據,同時避免另一個線程重新提取數據,因爲獲取鎖之前的空檢查失敗。另外,由於對函數的訪問量很大,我不能僅僅刪除第一個空檢查,因爲隨之而來的不必要的鎖定會掩蓋應用程序。 – Chris 2009-07-30 15:05:53

回答

8

大概你正在使用雙重檢查鎖定,因爲你有一個資源,你想以懶惰,線程安全的方式進行初始化。

爲了實現這一目的,雙選鎖定是一個機制,但正如您已經正確指出的那樣,機制的冗長性徹底超過了代碼的含義。

當你有一種機制模糊含義時,通過創建一個抽象來隱藏該機制。一種方法是創建一個「懶惰的線程安全實例」類,並將一個委託傳遞給它,它將以懶惰,線程安全的方式執行操作。

但是,還有更好的方法。更好的方法是不要自己做那些工作,而是讓世界級的線程專家爲你做。這樣你就不必擔心它是否正確。 Joe Duffy不得不擔心正確。正如Joe聰明地說過的那樣,不是重複遍佈整個地方的鎖定機制,而是寫一次然後使用抽象。

喬的代碼是在這裏:

http://www.bluebytesoftware.com/blog/PermaLink,guid,a2787ef6-ade6-4818-846a-2b2fd8bb752b.aspx

和該代碼的變化將在基類庫的下一個版本發佈。

1

爲了減少噪音,你可以這樣做:

public List<Mall> Malls() 
{ 
    EnsureMallsInitialized(); 
    return malls; 
} 

private void EnsureMallsInitialized() 
{ 
    if (malls == null) // not set 
    lock (_lock)  // get lock 
    if (malls == null) // still not set 
    { 
     InitializeMalls(); 
    }   
} 

private void InitializeMalls() 
{ 
    using (var session = NhibernateHelper.OpenSession()) 
    { 
     malls = session.CreateCriteria<Mall>() 
      .AddOrder(Order.Asc("Name")).List<Mall>(); 

     CacheManager.Set(CACHE_KEY, malls, TimeSpan.FromMinutes(CACHE_DURATION)); 
    } 
}