ConcurrentDictionary是否线程安全,以至于我可以将其用作静态缓存?

26

基本上,如果我想要做以下事情:

public class SomeClass
{
    private static ConcurrentDictionary<..., ...> Cache { get; set; }
}

这样做是否可以避免在许多地方使用lock

2个回答

40

是的,它是线程安全的,而且它避免了你在各个地方使用锁(不管那是什么意思)。当然,这只能为你提供对存储在此字典中的数据的线程安全访问,但如果数据本身不是线程安全的,则需要同步访问它。例如,假设您已将 List<T> 存储在此缓存中。现在,线程1以线程安全的方式从缓存中获取此列表(因为并发字典保证了这一点),然后开始枚举此列表。恰好在同一时间,线程2以线程安全的方式从缓存中获取完全相同的列表,并写入该列表(例如添加一个值)。结论:如果您没有同步线程1,它将遇到麻烦。

至于将其用作缓存,那可能不是一个好主意。对于缓存,我建议您使用框架中已经构建的内容。例如,MemoryCache 类。之所以这样做,是因为内置于System.Runtime.Caching程序集中的内容明确是为缓存而构建的 => 它处理诸如在内存不足时自动过期数据、缓存过期项的回调等事项,您甚至可以使用像 memcached、AppFabric 等东西将缓存分布在多个服务器上,这些都是您无法想象的并发字典所能实现的。


2
MemoryCache类像ConcurrentDictionary一样是线程安全的吗? - michael
1
@michael,是的,它是线程安全的,但绝对适用于同步访问可能存储在此缓存中的非线程安全对象的备注。 - Darin Dimitrov
哦,我明白那部分。但是,为了让其他读者能够理解,我要重申一下。你的意思是ConcurrentDictionaryMemoryCache类都是线程安全的,但其中的内容不保证是线程安全的。 :) - michael
@michael,没错,说得好。我的英语太差了,无法表达自己。 - Darin Dimitrov

3
你仍然可能需要像在数据库中需要事务一样使用锁定。 “并发”部分意味着字典将在多个线程之间继续正确地运行。 并发集合内置了TryGetValue和TryRemove,这表明有人可能会首先删除一个项目。 虽然在粒度级别上内置了锁定,但您仍然需要考虑在这些情况下该怎么做。 对于缓存来说,通常无关紧要-即它是幂等操作。
关于缓存。 我感觉它取决于您在缓存中存储什么以及您对其执行的操作。 使用对象会产生转换成本。 可能对于大多数基于Web的应用程序,如上所建议,MemCache更适合。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接