コードの一部を見てください:
class Program
{
static void Main(string[] args)
{
//开启两个线程
var threadOne = new Thread(new ThreadSample("ThreadOne").CountNumbersByLock);
threadOne.Start();
var threadTwo = new Thread(new ThreadSample("ThreadTwo").CountNumbersByLock);
threadTwo.Start();
//var threadOne = new Thread(new ThreadSample("ThreadOne").CountNumbersByMonitor);
//threadOne.Start();
//var threadTwo = new Thread(new ThreadSample("ThreadTwo").CountNumbersByMonitor);
//threadTwo.Start();
Console.ReadKey();
}
}
class ThreadSample
{
private readonly string _threadNo;
private readonly static object staticObject = new object();
public ThreadSample(string threadNo)
{
_threadNo = threadNo;
}
public void CountNumbersByLock()
{
Console.WriteLine($"线程 {_threadNo} 等待锁..... ");
lock (staticObject)
{
Console.WriteLine($"线程 {_threadNo} 获取锁..... ");
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine($"线程 {_threadNo} is count number..... ");
}
Console.WriteLine($"线程 {_threadNo} 释放锁..... ");
}
public void CountNumbersByMonitor()
{
bool isRequiredLock = false;
try
{
Console.WriteLine($"线程 {_threadNo} 等待锁..... ");
Monitor.Enter(staticObject, ref isRequiredLock);
Console.WriteLine($"线程 {_threadNo} 获取锁..... ");
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine($"线程 {_threadNo} is count number..... ");
}
finally
{
if (isRequiredLock)
{
Monitor.Exit(staticObject);
Console.WriteLine($"线程 {_threadNo} 释放锁..... ");
}
}
}
}
コールCountNumbersByLock結果:
コールCountNumbersByMonitor結果:
同じ結果、なぜ?キーロックを監視し、実際にシンタックスシュガーのユースケースのクラスです。ロック効果と同等に
bool isRequiredLock = false;
try
{
Monitor.Enter(staticObject, ref isRequiredLock);
// code
}
finally
{
if (isRequiredLock)
{
Monitor.Exit(staticObject);
// code
}
}
次に、デッドロックの例を見て:
class Program
{
static void Main(string[] args)
{
//开启两个线程
var threadOne = new Thread(new ThreadSample("ThreadOne").LockA);
threadOne.Start();
var threadTwo = new Thread(new ThreadSample("ThreadTwo").LockB);
threadTwo.Start();
Console.ReadKey();
}
}
class ThreadSample
{
private readonly string _threadNo;
private readonly static object staticObjectA = new object();
private readonly static object staticObjectB = new object();
public ThreadSample(string threadNo)
{
_threadNo = threadNo;
}
public void LockA()
{
Console.WriteLine($"线程 {_threadNo} 等待锁..... ");
lock (staticObjectA)
{
Thread.Sleep(TimeSpan.FromSeconds(2));
lock (staticObjectB)
{
Console.WriteLine($"线程 {_threadNo} 获取锁..... ");
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine($"线程 {_threadNo} is count number..... ");
}
}
Console.WriteLine($"线程 {_threadNo} 释放锁..... ");
}
public void LockB()
{
Console.WriteLine($"线程 {_threadNo} 等待锁..... ");
lock (staticObjectB)
{
Thread.Sleep(TimeSpan.FromSeconds(2));
lock (staticObjectA)
{
Console.WriteLine($"线程 {_threadNo} 获取锁..... ");
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine($"线程 {_threadNo} is count number..... ");
}
}
Console.WriteLine($"线程 {_threadNo} 释放锁..... ");
}
}
結果:
スレッド1と2は、デッドロックの形成に待っていました。
メソッドTryEnterモニタクラスの有効期限は、次のようにデッドロックThreadSampleは、クラスコードを修正避けるために、提供することができます。
class ThreadSample
{
private readonly string _threadNo;
private readonly static object staticObjectA = new object();
private readonly static object staticObjectB = new object();
public ThreadSample(string threadNo)
{
_threadNo = threadNo;
}
public void LockA()
{
Console.WriteLine($"线程 {_threadNo} 等待锁..... ");
if(Monitor.TryEnter(staticObjectA,TimeSpan.FromSeconds(3)))
{
Thread.Sleep(TimeSpan.FromSeconds(2));
if (Monitor.TryEnter(staticObjectB, TimeSpan.FromSeconds(3)))
{
Console.WriteLine($"线程 {_threadNo} 获取锁..... ");
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine($"线程 {_threadNo} is count number..... ");
}
}
Console.WriteLine($"线程 {_threadNo} 释放锁..... ");
}
public void LockB()
{
Console.WriteLine($"线程 {_threadNo} 等待锁..... ");
if (Monitor.TryEnter(staticObjectB, TimeSpan.FromSeconds(3)))
{
Thread.Sleep(TimeSpan.FromSeconds(2));
if (Monitor.TryEnter(staticObjectA, TimeSpan.FromSeconds(3)))
{
Console.WriteLine($"线程 {_threadNo} 获取锁..... ");
Thread.Sleep(TimeSpan.FromSeconds(2));
Console.WriteLine($"线程 {_threadNo} is count number..... ");
}
}
Console.WriteLine($"线程 {_threadNo} 释放锁..... ");
}
}
デバッグの結果:
上記のコードは、ロック・タイムアウト時間を設定し、3秒以内に、lockObjがロック解除された場合に3秒である、すなわち、3秒後、lockObjはTryEntryメソッド戻り、偽、ロック解除されていない、TryEntryは真を返します。私たちは、デッドロックを避けるために、このメソッドを使用することができます