4

查看 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));
}

这将出现在 ConcurrentDictionary 的 Intellisense 中,因为它实现了 ICollection 接口,许多开发人员甚至可能不知道有什么不妥(如果真的有什么?!)

编辑: 我所说的“隐式记录”的意思是 ConcurrentDictionary 实现了一组接口。它的文档说它的线程是安全的,但没有说明它是否仅适用于该页面上列出的方法,而是暗示实例上的所有操作都是安全的。

4

2 回答 2

0

你不会通过做你描述的事情来破坏 ConcurrentDictionary 的原子性。

您可能会导致并发字典中所有存储桶的不必要锁定。(通过以某些方式将其作为集合访问)

这会杀死字典的“并发”部分,并且效率低于仅用锁包围普通字典。

ConcurrentDictionary 令人敬畏的部分不是它是原子的——这可以很容易地用锁来完成,而是它是并发的,这意味着多个线程可以原子地写入它而不必相互等待。

一旦您对此有了更好的理解,您就会喜欢 GetOrAdd、TryRemove 和 TryUpdate 之类的东西,因为它们允许明确地转换到一个状态——即使您不确定之前的状态。

于 2014-08-22T07:26:10.140 回答
0

这是一个关于记录行为的问题。一般来说,您只能依靠记录在案的行为来实际持有。其他行为可以随时更改(在运行时、应用程序运行之间、框架补丁级别之间……)。

如果您可以在文档中找到这是安全的参考,那么您可以这样做。

如果没有,我通常会非常小心。另一方面,ConcurrentDictionary是核心类型,BCL 团队在其工作中应用了极端的兼容性标准。即使在没有记录的生产应用程序中,我也可以这样做。他们非常小心,即使在主要框架版本之间也不会破坏调用者。

由于这些兼容性保证并且这是一种核心类型,我可以从源代码中获取知识。

于 2014-06-08T13:54:18.327 回答