.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" 是什么意思? TryGetValueIDictionary<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> 的情况:

  • AddOrUpdateGetOrAdd 上的委托在线程安全问题上没有被调用。
  • 不保证在显式接口实现上调用的方法或属性是线程安全的;
  • 不保证在 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> 的实例,那么我应该知道是否应该存在线程安全问题。如果没有这样的担忧,我只是按原样使用字典,但如果需要线程安全,则我的责任执行所有操作线程安全的方式。