最近一個月一直在弄文件傳輸組件,其中用到多線程的技術,但有的地方確實須要只能有一個線程來操做,如何才能保證只有一個線程呢?首先想到的就是鎖的概念,最近在咱們項目組中聽的最多的也是鎖誰,如何鎖?看到有同事使用lock(this),也有lock(private static object),那就有點困惑了,lock到底鎖誰纔是最合適的呢?html
首先先上官方Msdn的說法安全
lock 關鍵字可確保當一個線程位於代碼的臨界區時,另外一個線程不會進入該臨界區。 若是其餘線程嘗試進入鎖定的代碼,則它將一直等待(即被阻止),直到該對象被釋放。
lock 關鍵字在塊的開始處調用 Enter,而在塊的結尾處調用 Exit。 ThreadInterruptedException 引起,若是 Interrupt 中斷等待輸入 lock 語句的線程。
一般,應避免鎖定 public 類型,不然實例將超出代碼的控制範圍。 多線程常見的結構 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 違反此準則:
若是實例能夠被公共訪問,將出現 lock (this) 問題。
若是 MyType 能夠被公共訪問,將出現 lock (typeof (MyType)) 問題。
因爲進程中使用同一字符串的任何其餘代碼都將共享同一個鎖,因此出現 lock("myLock") 問題。
最佳作法是定義 private 對象來鎖定, 或 private static 對象變量來保護全部實例所共有的數據。
在 lock 語句的正文不能使用 等待 關鍵字。函數
Enter指的是Monitor.Enter(獲取指定對象上的排他鎖。),Exit指的是Monitor.Exit(釋放指定對象上的排他鎖。)this
有上面msdn的解釋及Exit方法,能夠這樣猜想「直到該對象被釋放」,」該對象「應該是指鎖的對象,對象釋放了或者對象改變了,其餘的線程才能夠進入代碼臨界區(是否是能夠這樣來理解?)。spa
在多線程中,每一個線程都有本身的資源,可是代碼區是共享的,即每一個線程均可以執行相同的函數。這可能帶來的問題就是幾個線程同時執行一個函數,致使數據的混亂,產生不可預料的結果,所以咱們必須避免這種狀況的發生。線程
打個比方,有這樣一個情景,不少公司所在的大廈的廁所的蹲位都是小單間型的,也就是一次只能進去一我的,那麼爲了不每次進去一我的,那怎麼作呢?不就是一我的進去以後順手把門鎖上麼?這樣你在裏面幹啥事,外邊的人也只能等待你解放完了,才能進入。而蹲位的資源(蹲位,手紙等)是共享的。3d
最常使用的鎖是以下格式的代碼段:code
private static object objlock = new object(); lock (objlock ) { //要執行的代碼邏輯 }
爲何鎖的對象是私有的呢?仍是以廁所爲例子吧,私有就比如,這把鎖只有你能訪問到,並且最好這把鎖不會由於外力而有所改變,別人訪問不到,這樣才能保證你進去了,別人就進不去了,若是是公有的,就比如你蹲位小單間的鎖不是安裝在裏面而是安裝在外邊的,別人想不想進就不是你所能控制的了,這樣也不安全。htm
原文章列舉的demo沒法說明問題,已將原文章的demo刪除,將修改後的demo遷移到這篇文章。
答案是否認的,如
固然lock(null)也是不行的,如圖
雖然編譯能夠經過,可是運行就會出錯。
string也是應用類型,從語法上來講是沒有錯的。
可是鎖定字符串尤爲危險,由於字符串被公共語言運行庫 (CLR)「暫留」。 這意味着整個程序中任何給定字符串都只有一個實例,就是這同一個對象表示了全部運行的應用程序域的全部線程中的該文本。所以,只要在應用程序進程中的任何位置處具備相同內容的字符串上放置了鎖,就將鎖定應用程序中該字符串的全部實例。一般,最好避免鎖定 public 類型或鎖定不受應用程序控制的對象實例。例如,若是該實例能夠被公開訪問,則 lock(this) 可能會有問題,由於不受控制的代碼也可能會鎖定該對象。這可能致使死鎖,即兩個或更多個線程等待釋放同一對象。出於一樣的緣由,鎖定公共數據類型(相比於對象)也可能致使問題。並且lock(this)只對當前對象有效,若是多個對象之間就達不到同步的效果。lock(typeof(Class))與鎖定字符串同樣,範圍太廣了。
關於lock的介紹就到這裏,有下面幾點須要注意的地方
一、lock的是引用類型的對象,string類型除外。
二、lock推薦的作法是使用靜態的、只讀的、私有的對象。
三、保證lock的對象在外部沒法修改纔有意義,若是lock的對象在外部改變了,對其餘線程就會暢通無阻,失去了lock的意義。
@Aulan
this 表示的就是當前實例,當你再new一個的時候,鎖定的就再也不是同一個對象了。 不能鎖定值類型的緣由是,當這個值類型傳遞到另外一個線程的時候,會建立一個副本,鎖定的也再也不是同一個對象了。 鎖定字符串帶來的問題是,字符串在CLR中會暫存在 內存中,若是有兩個變量被分配了相同的字符串內容,那麼這兩個引用會指向同一塊內存,實際鎖定也就是同一個對象,這就會致使整個應用程序的阻塞。因此鎖定字符串是很是危險的行爲。
參考文章
http://www.cnblogs.com/jintianhu/archive/2010/11/19/1881494.html