【C#】lock語句及在單例模式中應用

C#中的lock語句是怎麼回事,有什麼作用?

C#中的lock語句將lock中的語句塊視爲臨界區,讓多線程訪問臨界區代碼時,必須順序訪問。他的作用是在多線程環境下,確保臨界區中的對象只被一個線程操作,防止出現對象被多次改變情況。

注意的地方有:lock對象必須是一個不可變對象,否則無法阻止另一個線程進入臨界區。最好是private static readonly 或者private static。常見的lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 都是不合理的寫法。

原因:

1.lock(this),主要問題是如果類爲實例化類,那麼this也只是當前實例,不能起到鎖定的作用,而且即使是靜態類可以被鎖定,那麼由於尺寸問題,不如鎖定不可變小對象合算。

2.lock(typeof())問題在於鎖定對象類型當相於鎖定類型中的靜態對象部分,鎖定了所有實例,速度慢;另一方面,有可能程序其他部分在訪問該對象,已經替您鎖定,將導致您鎖定語句的掛起。原文(Here's why: Since there's one type object for all instances of a class, it would appear that locking it would provide a lock equivalent to locking a static object contained in your class. You would lock all instances of the class, wait until other threads were done accessing any part of any instance, then lock access so you could access static members safely and without another thread interfering.)

3.lock("")問題在於微軟將內容相同的字符串視爲同一個對象,如果您在此鎖定了他,那麼其實是鎖定了同一個對象,將阻止其他地方對字符串的鎖定。

 

lock語句的一個典型應用就是單例模式。 而單例模式的一個最簡單實現方式就是用靜態對象方式。如下:

1
2
3
4
5
6
7
public class ABicycle {  
   private static ABicycle aBicycle = new ABicycle();  
    public ABicycle Instance()  
   {     
      return aBicycle;  
   }
}

 

這是實現單例模式最簡單的一種方式,但是有一個缺點就是假如ABicycle類被提前調用後,aBicycle即被實例化,沒法做到實例化延遲。在此情況下,利用一個關聯類可以避免此問題的發生。即:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ABicycle {  
  public ABicycle Instance()  
  {     
      return ABicycleStance.Instance();  
  }
}
private class ABicycleStance {  
   internal static readonly ABicycle aBicycle = new ABicycle();  
   public ABicycle Instance()  
   {     
      return aBicycle;  
   }
}

 

單例模式的一個思路是利用C#的lock語句實現。 最簡單實現方式爲:

1
if(... == null){ ... = new ... } return ...;

 

如果這樣實現,有一個問題無法迴避,即無法確保只能讓一個線程使對象實例化,因爲有可能多個線程併發執行到此,同時實例化了對象。爲此,需要引用lock語句。引用的方式也有講究,最直接的實現方式就是:

1
2
3
4
5
6
7
8
9
10
11
12
13
private static readonly locker = new object();
 
//或者這樣寫也可以。
 
//private static locker = new object();
 
lock(locker)
{  
  if(.. == null)  
  {   
     ...  
  }
}

 

上面做法可行,但是有一個問題是每次返回時首先要對locker上鎖,這樣就犧牲了一些本來不必犧牲的性能,因此,可以修改爲以下做法:

1
2
3
4
5
6
7
8
9
10
11
12
private static readonly locker = new object();
 
if(.. == null)  
{    
  lock(locker)    
  {      
      if(... == null)     
      {
 
      }   
   }
}

 

這樣,對於多線程來說是安全的,而且不必每次加鎖,只有在判斷對象沒有實例化時加鎖,避免了性能上的損失。


附上C#的一個模板父類

using UnityEngine;
using System.Collections;

public class Singleton<T> where T : class, new()
{
    private static T _instance;
    private static readonly object syslock = new object();

    public static T Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (syslock)
                {
                    if (_instance == null)
                    {
                        _instance = new T();
                    }
                }
            }
            return _instance;
        }
    }
}


參考資料:

http://msdn.microsoft.com/zh-cn/library/c5kehkcz.aspx

http://hi.baidu.com/benzhan/item/6304481419d6360dd1d66dff

http://bytes.com/topic/c-sharp/answers/249277-dont-lock-type-objects

原文鏈接:www.cnblogs.com/jizhong


發佈了106 篇原創文章 · 獲贊 24 · 訪問量 132萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章