线程安全集合

命名空间 System.Collections.Concurrent 包括多个集合类,这些类既是线程安全又可缩放的。 多个线程可以安全地高效地添加或删除这些集合中的项,而无需在用户代码中进行额外的同步。 编写新代码时,请使用并发集合类将多个线程同时写入集合。 如果只是从共享集合中读取,则可以使用命名空间中的 System.Collections.Generic 类。

System.Collections 和 System.Collections.Generic

命名空间中的 System.Collections 集合类包括 ArrayListHashtable。 这些类通过 Synchronized 属性提供一些线程安全性,该属性返回集合周围的线程安全包装器。 封装器的工作原理是在每次添加或删除操作时锁定整个集合。 因此,每个尝试访问集合的线程必须等待,直到轮到它获取锁定。 此过程不可缩放,并且可能会导致大型集合的性能显著下降。 此外,该设计不受争用条件的保护。 有关详细信息,请参阅 泛型集合中的同步

命名空间中的 System.Collections.Generic 集合类包括 List<T>Dictionary<TKey,TValue>。 与System.Collections类相比,这些类提供了更好的类型安全性和性能。 但是,类 System.Collections.Generic 不提供任何线程同步;当用户同时在多个线程上添加或删除项时,用户代码必须提供所有同步。

建议在命名空间中使用 System.Collections.Concurrent 并发集合类,因为它们提供类型安全性,而且更高效且完整的线程安全性。

细粒度锁定和无锁机制

某些并发集合类型使用轻型同步机制,例如SpinLockSpinWaitSemaphoreSlimCountdownEvent。 通常,这些同步类型在将线程置于实际 状态之前会在短时间内使用“繁忙旋转”Wait。 预计等待时间较短时,旋转比等待所消耗的计算资源少得多,因为后者涉及资源消耗量大的内核转换。 对于使用旋转的集合类,这种效率意味着多个线程可以高速率添加和删除项。 有关旋转与阻塞的详细信息,请参阅 SpinLockSpinWait

ConcurrentQueue<T>类和ConcurrentStack<T>类根本不使用锁。 相反,它们依赖于 Interlocked 操作实现线程安全性。

注释

由于并发集合类支持ICollection,因此它们为IsSynchronized属性和SyncRoot属性提供实现,即使这些属性无关。 IsSynchronized 始终返回 false,而 SyncRoot 始终是 null(在 Visual Basic 中为 Nothing)。

下表列出了命名空间中的 System.Collections.Concurrent 集合类型:

类型 DESCRIPTION
BlockingCollection<T> 为实现 IProducerConsumerCollection<T> 的所有类型提供限制和阻止功能。 有关详细信息,请参阅 BlockingCollection 概述
ConcurrentDictionary<TKey,TValue> 键值对字典的线程安全实现。
ConcurrentQueue<T> FIFO(先进先出)队列的线程安全实现。
ConcurrentStack<T> 后进先出(LIFO)堆栈的线程安全实现。
ConcurrentBag<T> 无序元素集合的线程安全实现。
IProducerConsumerCollection<T> 类型必须实现以在 BlockingCollection 中使用的接口。
标题 DESCRIPTION
BlockingCollection 概述 描述 BlockingCollection<T> 类型提供的功能。
如何:在 ConcurrentDictionary 中添加和删除项 介绍如何在 ConcurrentDictionary<TKey,TValue> 中添加和删除元素
如何:在 BlockingCollection 中逐个添加和取出项 介绍如何在不使用只读枚举器的情况下从阻塞集合中添加和检索项。
如何:向集合添加边界和阻止功能 介绍如何使用任何集合类作为 IProducerConsumerCollection<T> 集合的底层存储机制。
如何:使用 ForEach 删除 BlockingCollection 中的项目 介绍如何使用 foreachFor Each 在 Visual Basic 中)删除阻塞集合中的所有项。
如何在管道中使用阻塞集合数组 介绍如何同时使用多个阻塞集合来实现管道。
如何:使用 ConcurrentBag 创建对象池 演示如何在可重用对象而不是持续创建新对象的情况下使用并发包来提高性能。

参考文献