2009-07-18 53 views
1

我想實現我自己的提供商的XML網站地圖文件。因爲這個我已經開始研究通過反射器的默認微軟XmlSiteMapProvider,我發現一個片段是困惑我,這裏有雲:代碼剪斷的問題,我不明白

SiteMapNode node = this._siteMapNode; 
if (node != null) 
{ 
    return node; 
} 
XmlDocument configDocument = this.GetConfigDocument(); 
lock (base._lock) 
{ 
    **if (this._siteMapNode == null)** 
    {...// more code 

好吧,我們首先檢查節點是否不爲空,然後當支票已經過了,我們再次查看。是不是這個If語句是多餘的?或者它可能與鎖有關係?

回答

1

想象一下,如果多個線程幾乎同時運行這段代碼,會發生什麼情況。

兩個線程都可能到達第一個空檢查並決定創建一個新節點。該鎖確保只有一個線程進入第二個空塊並創建新節點。

您可能會問:爲什麼不鎖定第一個空檢查之前?原因是,在node而不是爲空的情況下,您希望代碼儘可能快,特別是在多線程正在運行的情況下,所以如果您希望它仍然爲空,然後您在內部確認鎖。

3

是的,它與鎖有關。可能是在第一次空檢查和鎖之間,另一個線程執行了相同的代碼並創建了節點,所以當第一個線程獲取鎖時,它不再爲空。這一點很重要要記住,當你有懶加載靜態資源:

private static List<string> _someStringList; 
private static object _lock = new object(); 
public static List<string> SomeStringList 
{ 
    get 
    { 
     if (_someStringList == null) 
     { 
      // if more than one thread try to do this at the same time 
      // it may be that the other thread has already gotten the lock 
      // and is creating the object at this point 
      lock (_lock) 
      { 
       // now we have the lock, so we check again to make 
       // sure that another thread did not get here first 
       if (_someStringList == null) 
       {     
        // now we know for sure that the object is not yet created, and 
        // also cannot have been created since we have the lock 
        _someStringList = new List<string>(); 
       } 
      } 
     } 
     return _someStringList; 
    } 
} 

在這樣做時,建議您使用用於鎖定的對象不用於別的,但它正在創建爲了這個目的。

2

是的,檢查兩次空稱爲Double-Checked Locking。你檢查null,獲取鎖,然後再次檢查null。這個想法是減少鎖定開銷,因爲如果第一個空檢查通過,對象已經被初始化,並且沒有理由再次通過鎖定/初始化步驟。您需要第二次空檢查,因爲該對象可能已由第一次空檢查和獲取鎖之間的不同線程初始化。