在C#编译器编译lock语句时,将其编译成了调用Monitor类。
语法如下
if(Monitor.TryEntry(lockObj, 1000))
{
try
{
}
finally
{
Monitor.Exit(lockObj);
}
}
else
{
// 超时后的处理代码
}
在Monitor.Enter 和 Try 方法之间可能会抛出异常。
例如在线程上调用Abort,或者是OutOfMemoryException。
为了解决这个问题CLR 4.0提供了Monitor.Enter的重载,增加了lockTaken 字段,当Monitor.Enter成功获取锁之后,lockTaken就是True,否则为False。
我们可以将上面的代码改成下面的版本。
bool lockTaken = false;try
{
Monitor.Enter(_locker, ref lockTaken);
// Do something..
}
finally{
if(lockTaken) {
Monitor.Exit(_locker);
}
}
Monitor类不仅可以完全取代lock语句(如果只使用lock语句本身的功能,最好还是直接用lock语句吧),还可以使用TryEntry方法设置一个锁定超时,单位是毫秒。
如下面的代码所示:
class Program
{
//在1秒中后,lockObj还未被解锁,TryEntry方法就会返回false,如果在1秒之内,lockObj被解锁,TryEntry返回true。我们可以使用这种方法来避免死锁,如下面的代码所示:
private static Object objA = new Object();
private static Object objB = new Object();
static void Main(string[] args)
{
Thread threadA = new Thread(LockA);
Thread threadB = new Thread(LockB);
threadA.Start();
threadB.Start();
Thread.Sleep(4000);
Console.WriteLine("线程结束");
}
public static void LockA()
{
if (Monitor.TryEnter(objA, 1000))//TryEntry方法设置一个锁定超时,单位是毫秒
{
Thread.Sleep(1000);
if (Monitor.TryEnter(objB, 2000))
{
Monitor.Exit(objB);
}
else
{
Console.WriteLine("LockB timeout");
}
Monitor.Exit(objA);
}
Console.WriteLine("LockA");
}
public static void LockB()
{
if (Monitor.TryEnter(objB, 2000))
{
Thread.Sleep(2000);
if (Monitor.TryEnter(objA, 1000))
{
Monitor.Exit(objA);
}
else
{
Console.WriteLine("LockA timeout");
}
Monitor.Exit(objB);
}
Console.WriteLine("LockB");
}
}