當多個線程在並發的時候,難免會碰到相互沖突的事情,比如最經典的ATM機的問題,並發不可怕,可怕的是我們沒有能力控制。
線程以我的理解可以分為三種
① 鎖。
② 互斥。
③ 信號。
好,這一篇主要整理“鎖”,C#提供了2種手工控制的鎖
一: Monitor類
這個算是實現鎖機制的純正類,在鎖定的臨界區中只允許讓一個線程訪問,其他線程排隊等待。主要整理為2組方法。
1:Monitor.Enter和Monitor.Exit
微軟很照護我們,給了我們語法糖Lock,對的,語言糖確實減少了我們不必要的勞動並且讓代碼更可觀,但是如果我們要精細的
控制,則必須使用原生類,這里要注意一個問題就是“鎖住什么”的問題,一般情況下我們鎖住的都是靜態對象,我們知道靜態對象
屬於類級別,當有很多線程共同訪問的時候,那個靜態對象對多個線程來說是一個,不像實例字段會被認為是多個。
2:Monitor.Wait和Monitor.Pulse
首先這兩個方法是成對出現,通常使用在Enter,Exit之間。
Wait: 暫時的釋放資源鎖,然后該線程進入”等待隊列“中,那么自然別的線程就能獲取到資源鎖。
Pulse: 喚醒“等待隊列”中的線程,那么當時被Wait的線程就重新獲取到了鎖。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace ConsoleApplication3 { class Program { static void Main(string[] args) { for (int i = 0; i < 100; i++) { Thread t = new Thread(run); t.Start(); } Console.ReadKey(); } static object obj = new object(); static int count = 0; static void run() { Thread.Sleep(10); Monitor.Enter(obj); Console.WriteLine(++count); Monitor.Exit(obj); } } }
using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace Test { public class Program { public static void Main(string[] args) { LockObj obj = new LockObj(); //注意,這里使用的是同一個資源對象obj Jack jack = new Jack(obj); John john = new John(obj); Thread t1 = new Thread(new ThreadStart(jack.Run)); Thread t2 = new Thread(new ThreadStart(john.Run)); t1.Start(); t1.Name = "Jack"; t2.Start(); t2.Name = "John"; Console.ReadLine(); } } //鎖定對象 public class LockObj { } public class Jack { private LockObj obj; public Jack(LockObj obj) { this.obj = obj; } public void Run() { Monitor.Enter(this.obj); Console.WriteLine("{0}:今天我值班嗎?看下", Thread.CurrentThread.Name); Console.WriteLine("{0}:原來是jon值班呀,那我走呀", Thread.CurrentThread.Name); //暫時的釋放鎖資源 Monitor.Wait(this.obj); Console.WriteLine("{0}:那行吧", Thread.CurrentThread.Name); //喚醒等待隊列中的線程 Monitor.Pulse(this.obj); Console.WriteLine("{0}:呵呵", Thread.CurrentThread.Name); Monitor.Exit(this.obj); } } public class John { private LockObj obj; public John(LockObj obj) { this.obj = obj; } public void Run() { Monitor.Enter(this.obj); Console.WriteLine("{0}:哥們,今天我有點事情,你幫我下唄", Thread.CurrentThread.Name); //喚醒等待隊列中的線程 Monitor.Pulse(this.obj); Console.WriteLine("{0}:謝謝兄弟了", Thread.CurrentThread.Name); //暫時的釋放鎖資源 Monitor.Wait(this.obj); Console.WriteLine("{0}:哈哈", Thread.CurrentThread.Name); Monitor.Exit(this.obj); } } }