System.Collections.Concurrent.ConcurrentDictionary的MSDN文档说:
线程安全
ConcurrentDictionary<TKey, TValue>
的所有公共成员和受保护成员都是线程安全的,可以从多个线程同时使用。但是,通过其中一个ConcurrentDictionary<TKey, TValue>
实现的接口访问的成员,包括扩展方法,不保证是线程安全的,可能需要通过呼叫者。
(强调我的)
这似乎是自相矛盾的。 “所有成员都是线程安全的。但成员[有时]不是线程安全的。”
我确实理解扩展方法当然不能保证是线程安全的。
但是“通过其中一个接口访问”是什么意思? TryGetValue
(IDictionary<TKey, TValue>
接口的成员)线程安全吗?
答案 0 :(得分:5)
请注意涵盖explicit interface implementations的文档部分。例如。该类实现IDictionary.Add
。此方法不是该类的公共或受保护成员,但可以通过IDictionary
接口访问。正是这些成员不能保证是线程安全的。
答案 1 :(得分:3)
the documentation中有一个特定部分明确表示ConcurrentDictionary<TKey, TValue>
中并非一切都是线程安全的:
所有这些操作都是原子操作,对
ConcurrentDictionary<TKey, TValue>
类的所有其他操作都是线程安全的。唯一的例外是接受委托的方法,即AddOrUpdate
和GetOrAdd
。对于字典的修改和写入操作,ConcurrentDictionary<TKey, TValue>
使用细粒度锁定来确保线程安全。 (对字典的读取操作是以无锁方式执行的。)但是,这些方法的委托在锁外部调用,以避免在锁定下执行未知代码时可能出现的问题。因此,这些代理执行的代码不受操作原子性的影响。
因此,有一些常规排除项和某些特定于ConcurrentDictionary<TKey, TValue>
的情况:
AddOrUpdate
和GetOrAdd
上的代表未被称为线程安全问题。答案 2 :(得分:3)
由于Explicit vs Implicit interface implementation。
如果查看source code for ConcurrentDictionary<TKey, TValue>
,您可能会看到有一些方法明确实现了一个接口(如object IDictionary.this[object key]
),虽然内部调用了同一操作的线程安全版本行为可能在未来发生变化。
将其视为责任分工:
如果我(作为一个类)收到ConcurrentDictionary<TKey, TValue>
的实例,我知道该实例有责任以线程安全的方式执行操作。
但是,如果我(再次作为一个类)收到IDictionary<TKey, TValue>
的实例,那么我应该知道是否应该存在线程安全问题。如果没有这样的问题我只是按原样使用字典,但是如果需要线程安全 我的责任以线程安全的方式执行所有操作。< / p>