多线程Monitor.TryEnter(有一个聪明的员工找老板。看到老板们在里面都掐成一团乱麻了,算了我还是撩吧)
下面代码展示死锁是怎么形成的,以及如何使用Monitor.TryEnter解除死锁
话不多说,还是直接看代码
先定义一个方法,以便给一会创建的子线程调用
static void LockTooMuch(object lock1, object lock2) { lock (lock1)//先锁定第一个对象 { Thread.Sleep(1000);//等待1秒 lock (lock2);//接着锁定第2个对象 } }
static void Main(string[] args)
{
object lock1 = new object();
object lock2 = new object();
//子线程使用LockTooMuch方法启动(此方法内部准备先锁定对象1,过一秒再锁定对象2,注意是准备!!并不是此时已经锁定了!!)
//【注意这个语句里锁定的2个对象,不一定优先于下面的主线程】
//下一句,主线程的语句lock(lock2)会先执行(主线程锁定)
new Thread(() => LockTooMuch(lock1, lock2)).Start();
//主线程先锁定对象2。注意,此时锁定lock2这行代码会先于上面一句执行(主线程总会比上面的子线程先一步执行)
//主线程锁定了对象2,而下一步子线程锁定了对象1,等待1秒(这时对象1还被锁定)。此时主线程要锁定对象1(这时对象1被子线程持有)。紧接着子线程要锁定对象2,而这时对象2还被主线程持有。
//所以死锁形成了!!!!!!!!!!!
lock (lock2)//主线程锁定了对象2(此时子线程锁定了对象1,并等待1秒(这时对象1还是被锁定))
{
Thread.Sleep(1000);
Console.WriteLine("Monitor.TryEnter allows not to get stuck, returning false after a specified timeout is elapsed");
if (Monitor.TryEnter(lock1, TimeSpan.FromSeconds(5)))//主线程要锁定对象1(这时对象1被子线程持有)(而且这时子线程要锁定对象2,而这时对象2还被主线程持有)
{
//Monitor.TryEnter的作用发挥了!!!!!!!等待5秒后超了,此时Monitor.TryEnter会直接返回false,所以不会造成死锁
Console.WriteLine("Acquired a protected resource succesfully");
}
else
{
Console.WriteLine("Timeout acquiring a resource!");
}
}
new Thread(() => LockTooMuch(lock1, lock2)).Start();
Console.WriteLine("----------------------------------");
lock (lock2)
{
Console.WriteLine("This will be a deadlock!");
Thread.Sleep(1000);
lock (lock1)
{
Console.WriteLine("Acquired a protected resource succesfully");
}
}
}