Lock和Monitor没区别,简单来讲Lock是Monitor的进一步封装
锁定的目的:由于多个线程并行/并发处理同一个“数据对象”(比如:在其它线程的某个地方发生了Clear、Add、Remove、Change等操作),导致“数据对象”不断变化,没法用了,所以,为了保证数据在某个计算时刻的“恒定”,使用排它锁将“数据对象”锁定,然后就视该“数据对象”为“一个恒定量”进行逻辑处理。
1.代码使用
Lock |
Monitor |
Lock(obj) { 执行任务 } |
Monitor.Enter(obj); try{ 执行任务 }finally { Monitor.Exit(obj); } |
2.Example
- 使用Task.WaitAll 等待子线程完成
- Monitor琐死要变化的参数,使其在使用时无法突变
- 使用Stopwatch观察子线程执行时长
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| static void Main() { Console.WriteLine("Monitor Demo ...");
int nTasks = 0; object obj = nTasks;
List<Task> tasks = new List<Task>();
try { Console.WriteLine($"nTasks:{nTasks};MainThreadId:{Thread.CurrentThread.ManagedThreadId}"); Stopwatch sw = new Stopwatch(); sw.Start(); for (int ctr=0;ctr<10;ctr++) { tasks.Add(Task.Run(async() => { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine($"子任务{Thread.CurrentThread.ManagedThreadId} 延时5000ms"); await Task.Delay(5000); Monitor.Enter(obj); try { nTasks++; Console.WriteLine($"nTasks:{nTasks};SubThreadId:{Thread.CurrentThread.ManagedThreadId}"); } finally { Monitor.Exit(obj); } })); } Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("不会堵塞"); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("使用Task.WaitAll(tasks.ToArray());等待tasks子线程结束,才执行主线程:等待子线程结束"); Task.WaitAll(tasks.ToArray()); sw.Stop(); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("开始执行主线程"); Console.WriteLine($"执行时长:{sw.ElapsedMilliseconds}ms"); Console.WriteLine($"nTasks:{nTasks};MainThreadId:{Thread.CurrentThread.ManagedThreadId}"); Console.ForegroundColor = ConsoleColor.White; } catch(AggregateException e) { String msg = String.Empty; foreach (var ie in e.InnerExceptions) { Console.WriteLine("{0}", ie.GetType().Name); if (!msg.Contains(ie.Message)) msg += ie.Message + Environment.NewLine; } Console.WriteLine("\nException Message(s):"); Console.WriteLine(msg); } Console.ReadLine(); }
|
效果