之前我们使用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实现将所有等待资源的线程由等待状态变为就绪状态,接下来如果资源被释放,所有就绪线程将均有机会获得资源并执行。