C#中,, 通過System.Threading.Monitor類可以實現(xiàn)多線程中對某些代碼塊的同步訪問,,以確保數(shù)據(jù)的安全性。 object obj=new object(); Monitor在鎖對象obj上會維持兩個線程隊列R和W以及一個引用T : (1) T是對當(dāng)前獲得了obj鎖的線程的引用(設(shè)此線程為CurrThread); (2) R為就緒隊列,, 其上的線程已經(jīng)準(zhǔn)備好獲取obj鎖,。當(dāng)obj鎖被CurrThread釋放后(CurrThread可通過Monitor.Exit(obj)或 Monitor.Wait(obj)來釋放其所獲的obj鎖)這些線程就會去競爭obj鎖,獲得obj鎖的線程將被T引用; 線程調(diào)用Monitor.Enter(obj)或Monitor.TryEnter(obj)將會使該線程直接進(jìn)入R隊列,。 (3) W為等待隊列,,其上的線程是因為調(diào)用了Monitor.Wait(obj)而進(jìn)入W隊列的;W上的線程不會被OS直接調(diào)度執(zhí)行,,也就是說它們沒有準(zhǔn)備好獲取obj鎖,,就是說在等待隊列上的線程不能去獲得obj鎖。當(dāng)前獲得obj鎖的線程CurrThread調(diào)用Monitor.Pulse(obj)或Monitor.PulseAll(obj)后會使W隊列中的第一個等待線程或所有等待線程被移至R隊列,,這時被移至R隊列的這些線程就有機(jī)會被OS直接調(diào)度執(zhí)行,,也就是有可以去競爭obj鎖。 lock 關(guān)鍵字lock 關(guān)鍵字可以作為Monitor類的一個替代,。下面兩個代碼塊是等效的: Monitor.Enter(this); //... Monitor.Exit(this);
lock (this) { //... } 在這里,,object 值與 lock 中的 object 值是一樣的。 class Program { public void PrintEven() { Monitor.Enter(this); try { for(int i = 0; i <= 10; i = i + 2) { Console.WriteLine(Thread.CurrentThread.Name + "--" + i); } } finally { Monitor.Exit(this); } } public void PrintOdd() { Monitor.Enter(this); try { for(int i = 1; i <= 10; i = i + 2) { Console.WriteLine(Thread.CurrentThread.Name + "--" + i); } } finally { Monitor.Exit(this); } } static void Main(string[] args) { Program program = new Program(); ThreadStart ts1 = new ThreadStart(program.PrintOdd); Thread t1 = new Thread(ts1); t1.Name = "打印奇數(shù)的線程"; t1.Start(); ThreadStart ts2 = new ThreadStart(program.PrintEven); Thread t2 = new Thread(ts2); t2.Name = "打印偶數(shù)的線程"; t2.Start(); } } 運行該程序,效果如下圖所示,。 Monitor 類的TryEnter() 方法在嘗試獲取一個對象上的顯式鎖方面和 Enter() 方法類似,。然而,它不像Enter()方法那樣會阻塞執(zhí)行,。如果線程成功進(jìn)入關(guān)鍵區(qū)域那么TryEnter()方法會返回true. Monitor 類的用法雖然比 lock 關(guān)鍵字復(fù)雜,,但其能添加等待獲得鎖定的超時值,這樣就不會無限期等待獲得對象鎖,。 Monitor.TryEnter(object, 毫秒數(shù) ); 該方法能在指定的毫秒數(shù)內(nèi)結(jié)束線程,,這樣能避免線程之間的死鎖現(xiàn)象。 C#中Monitor和Lock簡介及區(qū)別1.Monitor.Enter(object)方法是獲取鎖,Monitor.Exit(object)方法是釋放鎖,,這就是Monitor最常用的兩個方法,,當(dāng)然在使用過程中為了避免獲取鎖之后因為異常,致鎖無法釋放,,所以需要在try{} catch(){}之后的finally{}結(jié)構(gòu)體中釋放鎖(Monitor.Exit()),。 2.Monitor的常用屬性和方法: Enter(Object) 在指定對象上獲取排他鎖。 Exit(Object) 釋放指定對象上的排他鎖,。 IsEntered 確定當(dāng)前線程是否保留指定對象鎖,。 Pulse 通知等待隊列中的線程鎖定對象狀態(tài)的更改。 PulseAll 通知所有的等待線程對象狀態(tài)的更改,。 TryEnter(Object) 試圖獲取指定對象的排他鎖,。 TryEnter(Object, Boolean) 嘗試獲取指定對象上的排他鎖,并自動設(shè)置一個值,,指示是否得到了該鎖,。 Wait(Object) 釋放對象上的鎖并阻止當(dāng)前線程,直到它重新獲取該鎖,。 Lock關(guān)鍵字1.Lock關(guān)鍵字實際上是一個語法糖,,它將Monitor對象進(jìn)行封裝,給object加上一個互斥鎖,,A進(jìn)程進(jìn)入此代碼段時,,會給object對象加上互斥鎖,此時其他B進(jìn)程進(jìn)入此代碼段時檢查object對象是否有鎖,?如果有鎖則繼續(xù)等待A進(jìn)程運行完該代碼段并且解鎖object對象之后,B進(jìn)程才能夠獲取object對象為其加上鎖,,訪問代碼段,。 2.Lock關(guān)鍵字封裝的Monitor對象結(jié)構(gòu)如下: try { Monitor.Enter(obj); dosomething(); } catch(Exception ex) { } finally { Monitor.Exit(obj); } 3.鎖定的對象應(yīng)該聲明為private static object obj = new object();盡量別用公共變量和字符串、this,、值類型,。 Monitor和Lock的區(qū)別 1.Lock是Monitor的語法糖。 2.Lock只能針對引用類型加鎖,。 3.Monitor能夠?qū)χ殿愋瓦M(jìn)行加鎖,,實質(zhì)上是Monitor.Enter(object)時對值類型裝箱。 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() { //做具體的事情 } } |
|