當多個線程在並發的時候,難免會碰到相互沖突的事情,比如最經典的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);
}
}
}
