15

我正在尝试概述 C# 中的集合背后的线程安全理论。

为什么没有 Java 中的并发集合?(Java 文档)。有些集合看起来是线程安全的,但我不清楚该位置是什么,例如:

  • 复合操作,
  • 使用迭代器的安全性,
  • 写操作

我不想重新发明轮子!(我不是多线程专家,我绝对不会低估这将是多么困难)。

我希望社区可以提供帮助。

4

3 回答 3

29

.NET 到目前为止一直具有相对“低级”的并发支持 - 但 .NET 4.0 引入了System.Collections.Concurrent包含各种安全且有用的集合的命名空间。

就如何处理 .NET 4.0 之前的集合而言,Andrew 的回答当然是完全正确的——对于大多数用途,我只需在访问“正常”共享集合时适当地锁定即可。然而,并发集合使得使用生产者/消费者队列等变得容易。

于 2009-12-22T14:07:10.603 回答
19

C# 提供了几种跨多个线程处理集合的方法。为了更好地编写这些技术,我建议您从集合和同步(线程安全)开始:

默认情况下,Collections 类通常不是线程安全的。多位读者可以放心阅读收藏;但是,对集合的任何修改都会为访问该集合的所有线程(包括读取器线程)产生未定义的结果。

可以使用以下任何方法使集合类成为线程安全的:

  • 使用 Synchronized 方法创建一个线程安全的包装器,并通过该包装器以独占方式访问集合。
  • 如果该类没有 Synchronized 方法,则从该类派生并使用 SyncRoot 属性实现 Synchronized 方法。
  • 访问集合时,对 SyncRoot 属性使用锁定机制,例如 C# 中的 lock 语句(Visual Basic 中的 SyncLock)。
于 2009-12-22T13:59:34.327 回答
6

正如 Jon Skeet 所提到的,.NET 4 中的 System.Collections.Concurrent 命名空间中现在有“线程安全”集合。

在以前的 .NET Framework 版本中不存在并发集合(至少我的猜测)的原因之一是很难保证线程安全,即使使用并发集合也是如此。

(这并不完全正确,因为某些集合提供了 Synchronized 方法来从非线程安全集合返回线程安全集合,因此存在一些线程安全集合......)

例如,假设一个人有一个线程安全的字典 - 如果一个人只想在 Key 不存在的情况下进行插入,那么首先会查询集合以查看 Key 是否存在,然后如果 key 不存在则进行插入。但是,这两个操作不是线程安全的,在 ContainsKey 的查询和 Add 操作之间,另一个线程可能已经完成了该键的插入,因此存在竞争条件。

换句话说,集合的操作是线程安全的——但它的使用并不一定。在这种情况下,需要转换回传统的锁定技术(互斥锁/监视器/信号量...)以实现线程安全,因此并发收集在多线程安全方面没有为您带来任何好处(但性能可能更差) .

于 2009-12-22T14:23:03.630 回答