我正在尝试概述 C# 中的集合背后的线程安全理论。
为什么没有 Java 中的并发集合?(Java 文档)。有些集合看起来是线程安全的,但我不清楚该位置是什么,例如:
- 复合操作,
- 使用迭代器的安全性,
- 写操作
我不想重新发明轮子!(我不是多线程专家,我绝对不会低估这将是多么困难)。
我希望社区可以提供帮助。
我正在尝试概述 C# 中的集合背后的线程安全理论。
为什么没有 Java 中的并发集合?(Java 文档)。有些集合看起来是线程安全的,但我不清楚该位置是什么,例如:
我不想重新发明轮子!(我不是多线程专家,我绝对不会低估这将是多么困难)。
我希望社区可以提供帮助。
.NET 到目前为止一直具有相对“低级”的并发支持 - 但 .NET 4.0 引入了System.Collections.Concurrent
包含各种安全且有用的集合的命名空间。
就如何处理 .NET 4.0 之前的集合而言,Andrew 的回答当然是完全正确的——对于大多数用途,我只需在访问“正常”共享集合时适当地锁定即可。然而,并发集合使得使用生产者/消费者队列等变得容易。
C# 提供了几种跨多个线程处理集合的方法。为了更好地编写这些技术,我建议您从集合和同步(线程安全)开始:
默认情况下,Collections 类通常不是线程安全的。多位读者可以放心阅读收藏;但是,对集合的任何修改都会为访问该集合的所有线程(包括读取器线程)产生未定义的结果。
可以使用以下任何方法使集合类成为线程安全的:
- 使用 Synchronized 方法创建一个线程安全的包装器,并通过该包装器以独占方式访问集合。
- 如果该类没有 Synchronized 方法,则从该类派生并使用 SyncRoot 属性实现 Synchronized 方法。
- 访问集合时,对 SyncRoot 属性使用锁定机制,例如 C# 中的 lock 语句(Visual Basic 中的 SyncLock)。
正如 Jon Skeet 所提到的,.NET 4 中的 System.Collections.Concurrent 命名空间中现在有“线程安全”集合。
在以前的 .NET Framework 版本中不存在并发集合(至少我的猜测)的原因之一是很难保证线程安全,即使使用并发集合也是如此。
(这并不完全正确,因为某些集合提供了 Synchronized 方法来从非线程安全集合返回线程安全集合,因此存在一些线程安全集合......)
例如,假设一个人有一个线程安全的字典 - 如果一个人只想在 Key 不存在的情况下进行插入,那么首先会查询集合以查看 Key 是否存在,然后如果 key 不存在则进行插入。但是,这两个操作不是线程安全的,在 ContainsKey 的查询和 Add 操作之间,另一个线程可能已经完成了该键的插入,因此存在竞争条件。
换句话说,集合的操作是线程安全的——但它的使用并不一定。在这种情况下,需要转换回传统的锁定技术(互斥锁/监视器/信号量...)以实现线程安全,因此并发收集在多线程安全方面没有为您带来任何好处(但性能可能更差) .