本文只針對C#中,多線程同步所用到的鎖(lock)做爲研究對象。因爲想更直觀的顯示結果,因此,在作demo的時候,就把多線程經過事件操做UI的代碼也寫了出來,留做備忘和分享吧。多線程
其實多線程的同步,使用同步鎖的方法用了好屢次,今天無心中看到MSDN中,建議用:併發
1 private static readonly object locker1 = new object(); 2 private readonly object locker2 = new object();
備註:原文並無加readonly,是我後來本身加進去的。測試
我不只思考了一下他們的區別。this
而後我寫了一段代碼進行測試,測試類代碼以下:spa
/// <summary> /// 跨線程操做UI的時候傳遞的參數,本文爲了顯示消息,因此簡單的封裝了一個 /// </summary> public class MyEventArgs : EventArgs { public readonly string Message = string.Empty; public MyEventArgs(string msg) { this.Message = msg; } } /// <summary> /// 測試類,用於測試2種鎖的區別 /// </summary> public class LockTest { //2個鎖 private static readonly object Locker1 = new object(); private readonly object Locker2 = new object(); /// <summary> /// 跨線程操做UI的委託和事件 /// </summary> public delegate void MessageEventHandler(object sender, MyEventArgs e); public event MessageEventHandler MessageEvent; public void OnMessage(MyEventArgs e) { if (this.MessageEvent != null) MessageEvent(this, e); } //要鎖的變量,經過它能夠看出2種鎖在不一樣狀況下的效果 private int num = 0; //實例名字 private readonly string Name; public LockTest(string name) { Name = name; } //第一種鎖執行的方法 public void AddNum1() { lock (Locker1) { num = 0; ShowMessage(); } } //第二種鎖執行的方法 public void AddNum2() { lock (Locker2) { num = 0; ShowMessage(); } } //鎖內的一些操做,並經過事件,把關鍵的消息顯示到主線程中的UI裏 private void ShowMessage() { string msg = ""; for (int i = 0; i < 10; i++) { num += 1; msg = string.Format("線程 [{0}],實例[{1}]中num的值是[{2}]", Thread.CurrentThread.Name, this.Name, num); OnMessage(new MyEventArgs(msg)); Thread.Sleep(100); } msg = string.Format("======線程 [{0}]執行完畢======", Thread.CurrentThread.Name); OnMessage(new MyEventArgs(msg)); } }
測試用的類寫完了,開始測試:線程
首先測試單個實例、多線程,2種鎖的區別:code
private void button1_Click(object sender, EventArgs e) { LockTest test = new LockTest("LockTest 1"); test.MessageEvent += new LockTest.MessageEventHandler(MessageCallBack); listBox1.Items.Clear(); for (int i = 0; i <= 2; i++) { Thread a = new Thread(new ThreadStart(test.AddNum1)); a.Name = i.ToString(); a.Start(); } } private void button2_Click(object sender, EventArgs e) { LockTest test = new LockTest("LockTest 1"); test.MessageEvent += new LockTest.MessageEventHandler(MessageCallBack); listBox1.Items.Clear(); for (int i = 0; i <= 2; i++) { Thread a = new Thread(new ThreadStart(test.AddNum2)); a.Name = i.ToString(); a.Start(); } }
輸出結果如出一轍:
orm
得出結論:若是對一個實例,多線程訪問的時候,2種鎖是沒有區別的。對象
下面是測試多個實例的狀況(靜態鎖):blog
private void button3_Click(object sender, EventArgs e) { listBox1.Items.Clear(); for (int i = 0; i <= 2; i++) { LockTest test = new LockTest("LockTest " + i.ToString()); test.MessageEvent += new LockTest.MessageEventHandler(MessageCallBack); Thread a = new Thread(new ThreadStart(test.AddNum1)); a.Name = i.ToString(); a.Start(); } }
獲得結果:
得出結論,在靜態鎖面前,線程依舊要排隊,雖然不是一個實例,可是鎖是惟一的,線程只認鎖,因此線程並無併發!
繼續測試(非靜態的鎖):
private void button4_Click(object sender, EventArgs e) { listBox1.Items.Clear(); for (int i = 0; i <= 2; i++) { LockTest test = new LockTest("LockTest " + i.ToString()); test.MessageEvent += new LockTest.MessageEventHandler(MessageCallBack); Thread a = new Thread(new ThreadStart(test.AddNum2)); a.Name = i.ToString(); a.Start(); } }
獲得的結果:
得出結論:非靜態鎖的時候,多線程併發了,一塊兒在工做。
其實,測試的結果以前也能猜測出來,只不過,不測試下,內心老是以爲沒底,呵呵,測試完了,也就完全釋然了!
窗體中,用於事件回調,顯示到UI裏的代碼在這裏:
delegate void MessageHandler(string msg); public void MessageCallBack(object sender, MyEventArgs e) { MessageHandler handler = new MessageHandler(ShowMessage); this.Invoke(handler, new object[] { e.Message }); } public void ShowMessage(string msg) { this.listBox1.Items.Add(msg); }