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) 釋放對象上的鎖並阻止當前線程,直到它重新獲取該鎖。
Lock關鍵字
1.Lock關鍵字實際上是一個語法糖,它將Monitor對象進行封裝,給object加上一個互斥鎖,A進程進入此代碼段時,會給object對象加上互斥鎖,此時其他B進程進入此代碼段時檢查object對象是否有鎖?如果有鎖則繼續等待A進程運行完該代碼段並且解鎖object對象之后,B進程才能夠獲取object對象為其加上鎖,訪問代碼段。
2.Lock關鍵字封裝的Monitor對象結構如下:
try { Monitor.Enter(obj); dosomething(); } catch(Exception ex) { } finally { Monitor.Exit(obj); }
3.鎖定的對象應該聲明為private static object obj = new object();盡量別用公共變量和字符串、this、值類型。
Monitor和Lock的區別
1.Lock是Monitor的語法糖。
2.Lock只能針對引用類型加鎖。
3.(使用 Monitor 鎖定對象(即引用類型)而不是值類型。)。
4.Monitor還有其他的一些功能。
class Program { private static object obj = new object(); public void LockSomething() { lock (obj) { dosomething(); } } public void MonitorSomeThing() { try { Monitor.Enter(obj); dosomething(); } catch(Exception ex) { } finally { Monitor.Exit(obj); } } public void dosomething() { //做具體的事情 } }
Monitor 類通過向單個線程授予對象鎖來控制對對象的訪問。對象鎖提供限制訪問代碼塊(通常稱為臨界區)的能力。當一個線程擁有對象的鎖時,其他任何線程都不能獲取該鎖。還可以使用 Monitor 來確保不會允許其他任何線程訪問正在由鎖的所有者執行的應用程序代碼節,除非另一個線程正在使用其他的鎖定對象執行該代碼。
Monitor 具有以下功能:
-
它根據需要與某個對象相關聯。
-
它是未綁定的,也就是說可以直接從任何上下文調用它。
-
不能創建 Monitor 類的實例。
將為每個同步對象來維護以下信息:
-
對當前持有鎖的線程的引用。
-
對就緒隊列的引用,它包含准備獲取鎖的線程。
-
對等待隊列的引用,它包含正在等待鎖定對象狀態變化通知的線程。
-
下表描述了訪問同步對象的線程可以采取的操作:
操作
說明
Enter, TryEnter
獲取對象鎖。此操作同樣會標記臨界區的開頭。其他任何線程都不能進入臨界區,除非它使用其他鎖定對象執行臨界區中的指令。
釋放對象上的鎖以便允許其他線程鎖定和訪問該對象。在其他線程訪問對象時,調用線程將等待。脈沖信號用於通知等待線程有關對象狀態的更改。
向一個或多個等待線程發送信號。該信號通知等待線程鎖定對象的狀態已更改,並且鎖的所有者准備釋放該鎖。等待線程被放置在對象的就緒隊列中以便它可以最后接收對象鎖。一旦線程擁有了鎖,它就可以檢查對象的新狀態以查看是否達到所需狀態。
釋放對象上的鎖。此操作還標記受鎖定對象保護的臨界區的結尾。
使用 Enter 和 Exit 方法標記臨界區的開頭和結尾。如果臨界區是一個連續指令集,則由 Enter 方法獲取的鎖將保證只有一個線程可以使用鎖定對象執行所包含的代碼。在這種情況下,建議您將這些指令放在 try 塊中,並將 Exit 指令放在 finally 塊中。此功能通常用於同步對類的靜態或實例方法的訪問。如果實例方法需要同步線程訪問,則它將使用當前實例作為要鎖定的對象調用 Enter 和對應的 Exit 方法。由於只能有一個線程持有當前實例上的鎖,因此該方法一次只能由一個線程來執行。靜態方法是使用當前實例的 Type 作為鎖定對象以類似的方式來保護的。Enter 和 Exit 方法提供的功能與 C# lock 語句(在 Visual Basic 中為 SyncLock)提供的功能相同,區別在於 lock 和 SyncLock 以 try…finally 塊(在 Visual Basic 中為 Try…Finally)來包裝 Exit 方法,以確保釋放監視器。
如果臨界區跨越整個方法,則可以通過將 System.Runtime.CompilerServices.MethodImplAttribute 放置在方法上並在 MethodImplAttribute 的構造函數中指定 Synchronized 值來實現上述鎖定功能。使用該屬性后就不需要 Enter 和 Exit 語句了。請注意,該屬性將使當前線程持有鎖,直到方法返回;如果可以更早釋放鎖,則使用 Monitor 類或 C#lock 語句而不是該屬性。
盡管鎖定和釋放給定對象的 Enter 和 Exit 語句可以跨越成員或類的邊界或同時跨越兩者的邊界,但並不推薦這樣做。
當選擇要同步的對象時,應只鎖定私有或內部對象。鎖定外部對象可能導致死鎖,這是因為不相關的代碼可能會出於不同的目的而選擇鎖定相同的對象。
- 以上來自MSDN、
- @陳卧龍的博客