查看ConcurrentDictionary文档,它说明如下:
表示可以的线程安全的键/值对集合 由多个线程同时访问。
现在阅读本文时,我认为我可以调用ConcurrentDictionary API中的任何方法,它将是线程安全的...但是这意味着包含显式实现,我是否有这种保证?
我的例子是如果我想要一个原子操作从ConcurrentDictionary中删除一个项,如果它的值是某个值。
所以我可以这样做:
var concurrentDictionary = new ConcurrentDictionary<string, string>();
concurrentDictionary.TryAdd("hey", "ho");
((ICollection<KeyValuePair<string, string>>) concurrentDictionary).Remove(new KeyValuePair<string, string>("hey", "ho"));
现在我查看了源代码并且该操作既是原子的又是线程安全的,但事实上它不在ConcurrentDictionary API上意味着我不应该使用它...或者也许我正在使用它集合做我不应该做的事情。
我可以更进一步,编写以下扩展方法:
public static boolean TryRemove(this ICollection<KeyValuePair<TKey, TValue>> collection, TKey key, TValue value)
{
return collection.Remove(new KeyValuePair<TKey, TValue>(key, value));
}
这将出现在ConcoreDictionary的Intellisense中,因为它实现了ICollection接口,许多开发人员甚至可能都不知道有什么不妥(如果真的有什么?!)
修改 我所说的“隐式文档”是ConcurrentDictionary实现了一组接口。它的文档说它的线程是安全的,但是没有声明它是否仅用于该页面上列出的方法,但暗示实例上的所有操作都是安全的。
答案 0 :(得分:0)
这是关于记录行为的问题。通常,您只能依靠记录的行为来实际持有。其他行为可以随时改变(在运行时,在应用程序运行之间,在框架补丁级别之间......)。
如果您可以在文档中找到这是安全的参考,那么您可以这样做。
如果没有,我一般都会非常小心。另一方面,ConcurrentDictionary
是核心类型,BCL团队将极端兼容性标准应用于其工作。即使在生产应用程序中,如果没有记录,我也可以这样做。他们非常小心,即使在主要框架版本之间也不会破坏呼叫者。
由于这些兼容性保证,这是一种核心类型,我可以从source code中获取知识。
答案 1 :(得分:0)
通过执行您描述的内容,您不会破坏ConcurrentDictionary的原子性。
您可能会在并发字典中导致所有存储桶的不必要锁定。 (通过某种方式将其作为集合访问)
这会杀死字典中的“并发”部分,并且效率低于仅使用锁定的普通字典。
ConcurrentDictionary的很棒的部分并不是它是原子的 - 它可以很容易地用锁完成,它是并发的,这意味着多个线程可以原子地写入它而不必相互等待。
一旦你对此有了更好的认识,你就会欣赏GetOrAdd,TryRemove和TryUpdate这样的东西,因为它们允许明确地转换到状态 - 即使你不确定以前的状态。