c# - 在此 ConcurrentDictionary 缓存场景中是否需要锁定

标签 c# multithreading concurrency

我有以下代码来缓存我在多线程应用程序中使用的并发字典中的某个类的实例。

简单地说,当我用 id 参数实例化类时,它首先检查字典中是否存在具有给定 id 的 privateclass 实例,如果不存在,则创建 privateclass 的实例(这需要很长时间,有时需要几个秒),并将其添加到字典中以备将来使用。

public class SomeClass
{
    private static readonly ConcurrentDictionary<int, PrivateClass> SomeClasses =
        new ConcurrentDictionary<int, PrivateClass>();

    private readonly PrivateClass _privateClass;

    public SomeClass(int cachedInstanceId)
    {
        if (!SomeClasses.TryGetValue(cachedInstanceId, out _privateClass))
        {
            _privateClass = new PrivateClass(); // This takes long time
            SomeClasses.TryAdd(cachedInstanceId, _privateClass);
        }
    }

    public int SomeCalculationResult()
    {
        return _privateClass.CalculateSomething();
    }

    private class PrivateClass
    {
        internal PrivateClass()
        {
            // this takes long time
        }

        internal int CalculateSomething()
        {
            // Calculates and returns something
        }
    }
}

我的问题是,我是否需要在外部类构造函数的生成和赋值部分周围添加一个锁来确保此代码线程安全,或者它是否就这样好?

更新:

在 SLaks 的 suggestion 之后, 尝试使用 GetOrAdd() ConcurrentDictionary 的方法与 Lazy 的组合, 但不幸的是 PrivateClass 的构造函数仍然调用了不止一次。参见 https://gist.github.com/3500955用于测试代码。

更新 2: 你可以在这里看到最终的解决方案: https://gist.github.com/3501446

最佳答案

你在滥用 ConcurrentDictionary

在多线程代码中,永远不要检查某个项目是否存在,如果不存在则添加它。
如果两个线程同时运行该代码,它们最终都会添加它。

一般来说,这种问题有两种解决方案。您可以将所有这些代码封装在一个锁中,或者您可以通过一个原子操作将其重新设计为整个代码。

ConcurrentDictionary 就是为这种场景设计的。

你应该简单地调用

 _privateClass = SomeClasses.GetOrAdd(cachedInstanceId, key => new PrivateClass());

关于c# - 在此 ConcurrentDictionary 缓存场景中是否需要锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12163125/

相关文章:

c# - 这两种异步方法有什么区别?

c# - 如何使用 PerformanceCounter 类计算 CPU 使用率百分比?

c# - 从单元测试调用调度程序时传播在继续任务中引发的异常

javascript - 如何处理访问 javascript 中的数据结构的两个回调?

ios - addTask 和 addTaskUnlessCancelled Swift 之间的结构化并发差异

concurrency - 如何在Eclipse CDT中使用GCC/G++编译并运行C++0x?

c# - LINQ 方法将集合分组为具有指定元素数量的子组

java - java多线程程序中的Volatile变量

ios - SKNode线程安全吗?

java - Java中如何让一个线程从另一个线程 hibernate