之前我们使用lock快捷方式,实现了多线程对同一资源的共享。在C#中lock实际上是Monitor操作的简化版本。
下面使用Monitor来完成之前的lock功能,你可以在此做一下对照:
private static void MultiThreadSynergicWithMonitor()
{
int[] array = new int[3];
Thread producer = new Thread(() =>
{
int count = 0;
Random random = new Random();
while (true)
{
if (10 == count)
break;
Monitor.Enter(array);
array[0] = random.Next(10);
array[1] = random.Next(10);
array[2] = random.Next(10);
count++;
Console.WriteLine(String.Format("{0} work count:{1}。{2}-{3}-{4}", Thread.CurrentThread.Name, count, array[0], array[1], array[2]));
Monitor.Exit(array);
}
})
{
Name = "producer"
};
Thread customer = new Thread(() =>
{
int count = 0;
while (true)
{
if (10 == count)
break;
Monitor.Enter(array);
count++;
Console.WriteLine(String.Format("{0} work count:{1}。{2}-{3}-{4}", Thread.CurrentThread.Name, count, array[0], array[1], array[2]));
array[0] = 0;
array[1] = 0;
array[2] = 0;
Monitor.Exit(array);
}
})
{
Name = "customer"
};
producer.Start();
customer.Start();
}
通过对比聪明的你可定发现,lock(xx){ }等效于 Monitor.Enter(x'x)与Monitor.Exit(xx)的组合,实际上lock就是Monitor的语法糖。
因此Monitor比lock在控制线程协作方面更为 强大,如下:
/// <summary>
/// 多线程协作-Monitor方式
/// 成功解决多线程对单一资源的共享
/// 并解决多个线程间同步问题
/// </summary>
private static void MultiThreadSynergicWithMonitor()
{
int[] array = new int[3];
Thread producer = new Thread(() =>
{
int count = 0;
Random random = new Random();
while (true)
{
if (10 == count)
break;
Monitor.Enter(array);
array[0] = random.Next(10);
array[1] = random.Next(10);
array[2] = random.Next(10);
count++;
Console.WriteLine(String.Format("{0} work count:{1}。{2}-{3}-{4}", Thread.CurrentThread.Name, count, array[0], array[1], array[2]));
Monitor.Pulse(array);
Monitor.Wait(array);
}
Monitor.Exit(array);
})
{
Name = "producer"
};
Thread customer = new Thread(() =>
{
int count = 0;
while (true)
{
if (10 == count)
break;
Monitor.Enter(array);
count++;
Console.WriteLine(String.Format("{0} work count:{1}。{2}-{3}-{4}", Thread.CurrentThread.Name, count, array[0], array[1], array[2]));
array[0] = 0;
array[1] = 0;
array[2] = 0;
Monitor.Pulse(array);
Monitor.Wait(array);
}
Monitor.Exit(array);
})
{
Name = "customer"
};
producer.Start();
customer.Start();
}
上面的代码与之前的lock代码功能类似但却不相同,它实现了producer线程与customer线程的交替运行(与lock方式相比控制更加精细),再次建议你执行一下实际代码,你会很容易发现两者却别。
说明:
1、Monitor.Pulse(xx)实现通知等待xx资源的某一个线程由等待状态(等待队列)变更为就绪状态(就绪队列),从而做好准备在调用Monitor.Pulse(x'x)功能的线程释放资源时马上锁定释放的资源。
2、Monitor.Wait(xx)实现调用该方法的线程暂时释放锁定的资源,并让该线程进入等待线程队列。所以线程在调用该方法后会临时中断后续代码的执行,在该线程再次获得资源时,
将回到中断继续执行。
3、Monitor.PulseAll(xx)是Monitor.Pulse(xx)扩大版,如果你理解了Monitor.Pulse(xx)并且知道线程状态的变更(线程所属队列的变化),那么理解Monitor.PulseAll就简单多了。
Monitor.PulseAll实现将所有等待资源的线程由等待状态变为就绪状态,接下来如果资源被释放,所有就绪线程将均有机会获得资源并执行。