理解C#中List<T>的线程安全性:多线程AddItem输出结果疑问
问题原因
这个差异本质是多线程执行时序不可预测导致的,和不同模式下的线程调度逻辑、代码执行速度直接相关:
正常运行(Release模式)3行输出的逻辑
你代码中的Add和ToArray是两个独立的lock块,两个操作之间没有锁保护,允许被其他线程打断。
Release模式下代码执行效率极高,大概率会触发如下执行时序:
- 线程1先抢到锁执行
Add操作,此时_list内容为["Item 0"],释放锁 - 线程1立刻抢到第二次锁执行
ToArray,得到长度为1的数组["Item 0"],释放锁 - 线程1遍历数组输出1行内容
Item 0 - 在线程1执行输出的间隙,线程2抢到锁执行
Add操作,此时_list内容更新为["Item 0", "Item 1"],释放锁 - 线程2执行
ToArray得到长度为2的数组,遍历输出2行内容:Item 0、Item 1
三次输出加总就是你看到的3行结果。
调试模式4行输出的逻辑
调试模式下代码执行速度被大幅拖慢,且调试器的线程调度逻辑会让两个线程的执行步骤更分散,大概率触发如下时序:
- 线程1先抢到锁执行
Add,_list变为["Item 0"],释放锁 - 线程2抢到锁执行
Add,_list变为["Item 0", "Item 1"],释放锁 - 两个线程先后执行
ToArray操作,拿到的都是长度为2的数组 - 两个线程各输出2行内容,加总就是4行结果
补充说明
两种输出结果都是符合代码逻辑的合法结果,你只保证了Add和ToArray操作本身的原子性,并没有约束两个操作的执行先后顺序,出现两种输出都属于正常情况。
内容的提问来源于stack exchange,提问作者Ziv
相关产品推荐
相关产品推荐

