.NET中等待lock语句的线程是否按阻塞顺序进入锁?
C# lock语句是否保证线程按到达顺序获取锁?
我尚未针对该问题做过专门测试,但在其他需要此行为的测试中,我发现阻塞在lock语句上的线程似乎确实按到达锁代码段的顺序进入锁。这只是我的运气,还是该行为确实有保证?
更新
实际上,通过以下代码我已确认,使用lock()语句无法保证线程的有序执行。
public static void Main() { Object objLock = new Object(); Stopwatch perf = new Stopwatch(); foreach (var batch in Enumerable.Range(1, 20)) { perf.Restart(); var sequence = Enumerable.Range(1, 200); var tickets = new List<int>(); var threads = sequence.Select(item => { var thread = new Thread(() => { lock (objLock) { tickets.Add(item); Thread.Sleep(50); } }); Thread.Sleep(10); thread.Start(); return thread; }).ToArray(); foreach (var thread in threads) thread.Join(); Console.WriteLine($"Batch #{batch}, tickets: {String.Join(", ", tickets)} - " + (tickets.SequenceEqual(sequence) ? "OK" : "NOT FIFO!")); Console.WriteLine($"Performance: { perf.ElapsedMilliseconds} ms"); } Console.WriteLine(Environment.NewLine + "DONE"); Console.ReadLine(); }
结论
C#的lock语句本质是封装了Monitor.Enter和Monitor.Exit操作,它并不保证按先进先出(FIFO)的顺序授予锁。
CLR与操作系统的线程调度器没有对锁的获取顺序做强制约定,实际运行中线程获取锁的顺序会受线程优先级、系统负载、调度策略等多种因素影响。你之前观察到的“按顺序进入锁”只是偶然出现的情况,不能作为可靠的业务依赖。
你的测试代码也直接验证了这一点:当200个线程竞争同一把锁时,多数批次会输出NOT FIFO!,说明tickets列表的顺序与线程启动顺序不一致,完全打破了FIFO的预期。
如果业务场景需要严格的有序锁访问,不能依赖lock的偶然表现,建议手动基于队列+SemaphoreSlim实现有序锁,或者使用专门提供有序同步机制的组件。
内容的提问来源于stack exchange,提问作者whatever
相关产品推荐
相关产品推荐

