线程安全集合

.NET Framework 4 引入了 System.Collections.Concurrent 命名空间,此命名空间包含多个线程安全且可伸缩的集合类。 多个线程可以在这些集合中安全高效地添加或移除项,而无需在用户代码中执行其他同步。 在编写新代码时,只要将集合同时写入多个线程中,就请使用并发集合类。 如果仅从共享集合进行读取,则可使用 System.Collections.Generic 命名空间中的类。 建议您不要使用 1.0 集合类,除非您需要以 .NET Framework 1.1 或早期版本的运行时为目标。

.NET Framework 1.0 和 2.0 集合中的线程同步

可以在 System.Collections 命名空间中找到 .NET Framework 1.0 中引入的集合。 这些集合(包括常用的 ArrayListHashtable)通过 Synchronized 属性(此属性返回与集合有关的线程安全包装)提供某种线程安全性。 该包装的工作原理是:对每个添加或移除操作锁定整个集合。 因此,每个尝试访问集合的线程必须一直等待,直到轮到它来获取锁。 这是无法进行伸缩的,并且对于大型集合而言,将会导致性能显著降低。 此外,这一设计并不能完全防止出现争用情况。 有关更多信息,请参见 MSDN 网站上的 Synchronization in Generic Collections(泛型集合中的同步)。

可以在 System.Collections.Generic 命名空间中找到 .NET Framework 2.0 中引入的集合类。 这些集合类包括 List<T>Dictionary<TKey, TValue> 等。 与 .NET Framework 1.0 类相比,这些类提供的类型安全性和性能会更高。 不过,.NET Framework 2.0 集合类不提供任何线程同步;当同时在多个线程上添加或移除项时,用户代码必须提供所有同步。

建议您使用 .NET Framework 4 中的并发集合类,因为这些类不仅提供了 .NET Framework 2.0 集合类的类型安全性,而且还提供了比 .NET Framework 1.0 集合所提供的线程安全性更高效且更完整的线程安全性。

细粒度锁定和无锁机制

一些并发集合类型使用的是轻量同步机制,如 SpinLockSpinWaitSemaphoreSlimCountdownEvent,这些同步机制是 .NET Framework 4 中的新增功能。 通常,上述同步类型在将线程置于实际等待状态之前会在短时间内使用“繁忙旋转”。 如果预计等待时间会非常短,则旋转所消耗的计算资源将比等待所消耗的计算资源少得多,因为后者涉及将消耗大量资源的内核转换。 对于使用旋转的集合类,这种效率意味着多个线程能够以非常快的速率添加和移除项。 有关旋转与 阻塞的更多信息,请参见 SpinLockSpinWait

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

注意注意

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

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

类型

说明

BlockingCollection<T>

提供针对实现 IProducerConsumerCollection<T> 的任何类型的限制和阻塞功能。 有关更多信息,请参见 BlockingCollection 概述

ConcurrentDictionary<TKey, TValue>

键/值对字典的线程安全实现。

ConcurrentQueue<T>

FIFO(先进先出)队列的线程安全实现。

ConcurrentStack<T>

LIFO(后进先出)堆栈的线程安全实现。

ConcurrentBag<T>

无序的元素集合的线程安全实现。

IProducerConsumerCollection<T>

类型必须实现以在 BlockingCollection 中使用的接口。

相关主题

标题

说明

BlockingCollection 概述

描述 BlockingCollection<T> 类型提供的功能。

如何:在 ConcurrentDictionary 中添加和移除项

描述如何从 ConcurrentDictionary<TKey, TValue> 添加和移除元素。

如何:在 BlockingCollection 中逐个添加和取出项

描述如何在不使用只读枚举器的情况下从阻塞集合添加和检索项。

如何:向集合类添加限制和阻塞功能

描述如何将任一集合类用作 IProducerConsumerCollection<T> 集合的基础存储机制。

如何:使用 ForEach 移除 BlockingCollection 中的项

描述如何使用 foreach(在 Visual Basic 中为 For Each)移除阻塞集合中的所有项。

如何:在管道中使用阻塞集合的数组

描述如何同时使用多个阻塞集合来实现一个管道。

如何:使用 ConcurrentBag 创建目标池

演示如何使用并发包在可重用对象(而不是继续创建新对象)的情况下改进性能。

引用

System.Collections.Concurrent