.NET 的 ConcurrentDictionary 的哪些成员是线程安全的?
Which members of .NET's ConcurrentDictionary are thread-safe?
System.Collections.Concurrent.ConcurrentDictionary 的 MSDN 文档说:
Thread Safety
All public and protected members of ConcurrentDictionary<TKey, TValue>
are thread-safe and may be used concurrently from multiple threads. However, members accessed through one of the interfaces the ConcurrentDictionary<TKey, TValue>
implements, including extension methods, are not guaranteed to be thread safe and may need to be synchronized by the caller.
(强调我的)
这似乎是自相矛盾的。 "All members are thread-safe. But members [sometimes] are not thread-safe."
我明白扩展方法当然不能保证线程安全。
但是 "accessed through one of the interfaces" 是什么意思? TryGetValue
(IDictionary<TKey, TValue>
接口的成员)是线程安全的吗?
the documentation 中有一个特定的部分明确指出 ConcurrentDictionary<TKey, TValue>
中并非所有内容都是线程安全的:
All these operations are atomic and are thread-safe with regards to all other operations on the ConcurrentDictionary<TKey, TValue>
class. The only exceptions are the methods that accept a delegate, that is, AddOrUpdate
and GetOrAdd
. For modifications and write operations to the dictionary, ConcurrentDictionary<TKey, TValue>
uses fine-grained locking to ensure thread safety. (Read operations on the dictionary are performed in a lock-free manner.) However, delegates for these methods are called outside the locks to avoid the problems that can arise from executing unknown code under a lock. Therefore, the code executed by these delegates is not subject to the atomicity of the operation.
所以有一些一般的排除和一些特定于 ConcurrentDictionary<TKey, TValue>
的情况:
AddOrUpdate
和 GetOrAdd
上的委托在线程安全问题上没有被调用。
- 不保证在显式接口实现上调用的方法或属性是线程安全的;
- 不保证在 class 上调用的扩展方法是线程安全的;
- class 的 public 成员上的所有其他操作都是线程安全的。
请注意涵盖 explicit interface implementations 的文档部分。例如。 class 实现了 IDictionary.Add
。此方法不是 public 或class 的受保护成员,但可以通过IDictionary
接口访问。正是这些这样的成员不能保证线程安全。
由于 Explicit vs Implicit interface implementation.
如果你看一下 source code for ConcurrentDictionary<TKey, TValue>
,你可能会发现有一些方法显式地实现了一个接口(比如 object IDictionary.this[object key]
),虽然在内部调用了相同的线程安全版本操作此行为将来可能会改变。
将其视为职责分工:
如果我(作为 class)接收到 ConcurrentDictionary<TKey, TValue>
的实例,我知道该实例有责任以线程安全的方式执行操作。
但是,如果我(再次作为 class)接收到 IDictionary<TKey, TValue>
的实例,那么我应该知道是否应该存在线程安全问题。如果没有这样的担忧,我只是按原样使用字典,但如果需要线程安全,则我的责任执行所有操作线程安全的方式。
System.Collections.Concurrent.ConcurrentDictionary 的 MSDN 文档说:
Thread Safety
All public and protected members of
ConcurrentDictionary<TKey, TValue>
are thread-safe and may be used concurrently from multiple threads. However, members accessed through one of the interfaces theConcurrentDictionary<TKey, TValue>
implements, including extension methods, are not guaranteed to be thread safe and may need to be synchronized by the caller.
(强调我的)
这似乎是自相矛盾的。 "All members are thread-safe. But members [sometimes] are not thread-safe."
我明白扩展方法当然不能保证线程安全。
但是 "accessed through one of the interfaces" 是什么意思? TryGetValue
(IDictionary<TKey, TValue>
接口的成员)是线程安全的吗?
the documentation 中有一个特定的部分明确指出 ConcurrentDictionary<TKey, TValue>
中并非所有内容都是线程安全的:
All these operations are atomic and are thread-safe with regards to all other operations on the
ConcurrentDictionary<TKey, TValue>
class. The only exceptions are the methods that accept a delegate, that is,AddOrUpdate
andGetOrAdd
. For modifications and write operations to the dictionary,ConcurrentDictionary<TKey, TValue>
uses fine-grained locking to ensure thread safety. (Read operations on the dictionary are performed in a lock-free manner.) However, delegates for these methods are called outside the locks to avoid the problems that can arise from executing unknown code under a lock. Therefore, the code executed by these delegates is not subject to the atomicity of the operation.
所以有一些一般的排除和一些特定于 ConcurrentDictionary<TKey, TValue>
的情况:
AddOrUpdate
和GetOrAdd
上的委托在线程安全问题上没有被调用。- 不保证在显式接口实现上调用的方法或属性是线程安全的;
- 不保证在 class 上调用的扩展方法是线程安全的;
- class 的 public 成员上的所有其他操作都是线程安全的。
请注意涵盖 explicit interface implementations 的文档部分。例如。 class 实现了 IDictionary.Add
。此方法不是 public 或class 的受保护成员,但可以通过IDictionary
接口访问。正是这些这样的成员不能保证线程安全。
由于 Explicit vs Implicit interface implementation.
如果你看一下 source code for ConcurrentDictionary<TKey, TValue>
,你可能会发现有一些方法显式地实现了一个接口(比如 object IDictionary.this[object key]
),虽然在内部调用了相同的线程安全版本操作此行为将来可能会改变。
将其视为职责分工:
如果我(作为 class)接收到 ConcurrentDictionary<TKey, TValue>
的实例,我知道该实例有责任以线程安全的方式执行操作。
但是,如果我(再次作为 class)接收到 IDictionary<TKey, TValue>
的实例,那么我应该知道是否应该存在线程安全问题。如果没有这样的担忧,我只是按原样使用字典,但如果需要线程安全,则我的责任执行所有操作线程安全的方式。