我将假设您的意思是 writeContainsKey
而不是Contains
. Contains
on aDictionary
是显式实现的,因此无法通过您声明的类型访问它。1
您的代码不安全。原因是没有什么可以同时阻止ContainsKey
和Add
执行。实际上,这会引入一些非常显着的失败场景。因为我查看了如何Dictionary
实现,所以我可以看到您的代码可能会导致数据结构包含重复项的情况。我的意思是它实际上包含重复项。不一定会抛出异常。其他的失败场景越来越陌生,但我不会在这里讨论。
对您的代码的一项微不足道的修改可能涉及双重检查锁定模式的变体。
public void MyMethod(string a)
{
if (!dictionary.ContainsKey(a))
{
lock (dictionary)
{
if (!dictionary.ContainsKey(a))
{
dictionary.Add(a, "someothervalue");
}
}
}
}
当然,由于我已经说过的原因,这并不安全。实际上,众所周知,除了最简单的情况(例如单例的规范实现),双重检查锁定模式很难在所有情况下都正确。这个主题有很多变化。您可以尝试使用TryGetValue
默认索引器,但最终所有这些变体都是大错特错。
那么如何在没有锁定的情况下正确完成呢?你可以试试ConcurrentDictionary
。它具有GetOrAdd
在这些场景中真正有用的方法。你的代码看起来像这样。
public void MyMethod(string a)
{
// The variable 'dictionary' is a ConcurrentDictionary.
dictionary.GetOrAdd(a, "someothervalue");
}
这就是它的全部。该GetOrAdd
函数将检查该项目是否存在。如果没有,那么它将被添加。否则,它将不理会数据结构。这一切都以线程安全的方式完成。在大多数情况下,ConcurrentDictionary
无需等待锁即可执行此操作。2
1顺便说一句,你的变量名也很讨厌。如果不是因为 Servy 的评论,我可能已经错过了我们谈论的是 aDictionary
而不是 a的事实List
。事实上,根据Contains
通话,我首先认为我们在谈论一个List
.
2读卡器完全无锁。ConcurrentDictionary
但是,编写者总是持有锁(即添加和更新;删除操作仍然是无锁的)。这包括GetOrAdd
功能。不同之处在于数据结构维护了几个可能的锁定选项,因此在大多数情况下很少或没有锁定争用。这就是为什么这种数据结构被称为“低锁”或“并发”而不是“无锁”的原因。