- 本代码演示了一个常见的多线程错误“死锁(deadlock)”。main方法中第一部分演示用Monitor避免死锁,第二部分用lock创建死锁,而死锁后程序会停止工作。
static void Main(string[] args)
{
#region 1.11
object lock1 = new object();
object lock2 = new object();
#region 演示:Monitor避免死锁
new Thread(() => Class1_11.LockTooMuch(lock1, lock2)).Start();
lock (lock2)
{
Thread.Sleep(1000);
Console.WriteLine("Monitor.TryEnter allows not to get stuck,returning false after a specified timeout is elapsed");//monitor.tryenter允许不卡住,在经过指定的超时后返回false
if (Monitor.TryEnter(lock1, 1000))
{
Console.WriteLine("成功获取受保护的资源");
}
else
{
Console.WriteLine("获取资源超时!");
}
}
Console.WriteLine("--------");
#endregion
#region 演示:lock创建死锁
new Thread(() => Class1_11.LockTooMuch(lock1, lock2)).Start();
lock (lock2)
{
Console.WriteLine("将发生死锁!");
Thread.Sleep(1000);
lock (lock1)
{
Console.WriteLine("成功获取受保护的资源");
}
}
#endregion
}
public class Class1_11
{
public static void LockTooMuch(object lock1, object lock2)
{
lock (lock1)//先锁住第一个对象lock1,过1s后锁住第二个对象lock2.然后在另一个线程
{
Thread.Sleep(1000);
lock (lock2);
}
}
}
- 代码解读:
LockTooMuch方法:先锁住第一个对象lock1,过1s后锁住第二个对象lock2。然后在另一个线程中启动该方法,尝试在主线程中先后锁第二个和第一个对象。
第二部分用lock关键字的代码,会造成死锁。第一个线程保持对lock1对象的锁定,等待直到lock2对象被释放。主线程保持对lock2的锁定并等待直到lock1释放,但是lock1永远不会被释放。
lock关键字是Monitor类用例的一个语法糖。我们分解使用了lock关键字的代码,会看到如下代码:
bool acquiredLock=false; try{ Monitor.Enter(lockObject,ref acquiredLock); }finally{ if(acquiredLock) { Monitor.Exit(lockObject); } }
所以,我们可以直接用Monitor类。它有TryEnter方法,该方法接受一个超时参数。获取资源超时,会返回false。