天天看點

鎖、C#中Monitor和Lock以及差別

1.Monitor.Enter(object)方法是擷取鎖,Monitor.Exit(object)方法是釋放鎖,這就是Monitor最常用的兩個方法,當然在使用過程中為了避免擷取鎖之後因為異常,緻鎖無法釋放,是以需要在try{} catch(){}之後的finally{}結構體中釋放鎖(Monitor.Exit())。

  2.Monitor的常用屬性和方法:

    Enter(Object) 在指定對象上擷取排他鎖。

    Exit(Object) 釋放指定對象上的排他鎖。

    IsEntered 确定目前線程是否保留指定對象鎖。

    Pulse 通知等待隊列中的線程鎖定對象狀态的更改。

    PulseAll 通知所有的等待線程對象狀态的更改。

    TryEnter(Object) 試圖擷取指定對象的排他鎖。

    TryEnter(Object, Boolean) 嘗試擷取指定對象上的排他鎖,并自動設定一個值,訓示是否得到了該鎖。

    Wait(Object) 釋放對象上的鎖并阻止目前線程,直到它重新擷取該鎖。

  1.Lock關鍵字實際上是一個文法糖,它将Monitor對象進行封裝,給object加上一個互斥鎖,A程序進入此代碼段時,會給object對象加上互斥鎖,此時其他B程序進入此代碼段時檢查object對象是否有鎖?如果有鎖則繼續等待A程序運作完該代碼段并且解鎖object對象之後,B程序才能夠擷取object對象為其加上鎖,通路代碼段。

  2.Lock關鍵字封裝的Monitor對象結構如下:

 3.鎖定的對象應該聲明為private static object obj = new object();盡量别用公共變量和字元串、this、值類型。

Monitor和Lock的差別

  1.Lock是Monitor的文法糖。

  2.Lock隻能針對引用類型加鎖。

  3.(使用 Monitor 鎖定對象(即引用類型)而不是值類型。)。

  4.Monitor還有其他的一些功能。

Monitor 類通過向單個線程授予對象鎖來控制對對象的通路。對象鎖提供限制通路代碼塊(通常稱為臨界區)的能力。當一個線程擁有對象的鎖時,其他任何線程都不能擷取該鎖。還可以使用 Monitor 來確定不會允許其他任何線程通路正在由鎖的所有者執行的應用程式代碼節,除非另一個線程正在使用其他的鎖定對象執行該代碼。

Monitor 具有以下功能:

它根據需要與某個對象相關聯。

它是未綁定的,也就是說可以直接從任何上下文調用它。

不能建立 Monitor 類的執行個體。

将為每個同步對象來維護以下資訊:

對目前持有鎖的線程的引用。

對就緒隊列的引用,它包含準備擷取鎖的線程。

對等待隊列的引用,它包含正在等待鎖定對象狀态變化通知的線程。

下表描述了通路同步對象的線程可以采取的操作:

操作

說明

擷取對象鎖。此操作同樣會标記臨界區的開頭。其他任何線程都不能進入臨界區,除非它使用其他鎖定對象執行臨界區中的指令。

<a href="https://msdn.microsoft.com/zh-cn/library/system.threading.monitor.wait(v=vs.80).aspx">Wait</a>

釋放對象上的鎖以便允許其他線程鎖定和通路該對象。在其他線程通路對象時,調用線程将等待。脈沖信号用于通知等待線程有關對象狀态的更改。

向一個或多個等待線程發送信号。該信号通知等待線程鎖定對象的狀态已更改,并且鎖的所有者準備釋放該鎖。等待線程被放置在對象的就緒隊列中以便它可以最後接收對象鎖。一旦線程擁有了鎖,它就可以檢查對象的新狀态以檢視是否達到所需狀态。

<a href="https://msdn.microsoft.com/zh-cn/library/system.threading.monitor.exit(v=vs.80).aspx">Exit</a>

釋放對象上的鎖。此操作還标記受鎖定對象保護的臨界區的結尾。

盡管鎖定和釋放給定對象的 Enter 和 Exit 語句可以跨越成員或類的邊界或同時跨越兩者的邊界,但并不推薦這樣做。

當選擇要同步的對象時,應隻鎖定私有或内部對象。鎖定外部對象可能導緻死鎖,這是因為不相關的代碼可能會出于不同的目的而選擇鎖定相同的對象。

以上來自MSDN、

@陳卧龍的部落格