我试图概述C#中集合背后的线程安全理论。
为什么Java中没有并发集合? (java docs)。有些集合看起来是线程安全的,但我不清楚它的位置是什么,例如关于:
我不想重新发明轮子! (我不是一个多线程大师,绝对不会低估这有多难)。
我希望社区可以提供帮助。
答案 0 :(得分:28)
System.Collections.Concurrent
命名空间,其中包含各种安全且有用的集合。
安德鲁的答案在如何在.NET 4.0之前处理集合方面是完全正确的 - 对于大多数使用我只是在访问“普通”共享集合时适当锁定。但是,并发集合使得使用生产者/消费者队列等变得容易。
答案 1 :(得分:19)
C#提供了多种方式来处理跨多个线程的集合。为了更好地记录这些技术,我建议您从Collections and Synchronization (Thread Safety)开始:
默认情况下,Collections类是 一般不是线程安全的。多 读者可以阅读该集合 置信度;但是,任何修改 到集合产生undefined 所有访问的线程的结果 该系列包括读者 线程。
集合类可以成为线程 安全使用以下任何一种方法 方法:
- 使用Synchronized方法创建一个线程安全的包装器 专门访问该集合 通过那个包装。
- 如果该类没有Synchronized方法,则派生自 类和实现同步 使用SyncRoot属性的方法。
- 使用锁定机制,例如C#中的lock语句(SyncLock in Visual Basic上的,在SyncRoot上 访问时的财产 集合。
答案 2 :(得分:6)
正如Jon Skeet所提到的,.NET 4中的System.Collections.Concurrent命名空间中现在有“线程安全”集合。
在以前的.NET Framework版本中不存在并发集合(至少我的猜测)的原因之一是,即使使用并发集合,也很难保证线程安全。
(这不完全正确,因为有些集合提供了一个Synchronized方法来从非线程安全集合返回线程安全集合,因此有一些线程安全集合......)
例如,假设一个人有一个线程安全的字典 - 如果一个人只想知道一个插入,如果Key不存在,那么首先会查询该集合以查看该Key是否存在,然后如果该键存在则会插入一个不存在。这两个操作不是线程安全的,但是在ContainsKey的查询和Add操作之间,另一个线程可能已经完成了该键的插入,因此存在竞争条件。
另一方面,集合的操作是线程安全的 - 但它的使用不一定。在这种情况下,需要转换回传统的锁定技术(互斥锁/监视器/信号量......)以实现线程安全性,因此并发收集在多线程安全性方面没有给您带来任何好处(但可能性能更差)