潜在的并发问题?

nfp*_*lee 2 c# asp.net-mvc concurrency multithreading

我一直在构建ASP.NET MVC应用程序,当我启动它时,我担心潜在的多线程问题.一个特别值得关注的是以下代码:

private static IDictionary<string, ISettings> _settingsDictionary = new Dictionary<string, ISettings>();

public T Settings<T>() where T : ISettings, new() {
    var key = typeof(T).FullName;

    if (!_settingsDictionary.ContainsKey(key))
        _settingsDictionary[key] = _settingsService.GetSettings<T>();

    return (T)_settingsDictionary[key];
}
Run Code Online (Sandbox Code Playgroud)

请注意,字典定义为静态.这允许我缓存字典,以便它为应用程序长度的每个请求返回相同的实例.

这在本地测试时工作正常,但我担心它可能会被数百名用户使用.这让我研究了ConcurrencyDictionary.请问你能告诉我是否需要使用它以及如果是这样的话我会怎么做.

谢谢

Tud*_*dor 6

是的,这里有潜在的数据竞争:

if (!_settingsDictionary.ContainsKey(key))
    _settingsDictionary[key] = _settingsService.GetSettings<T>();
Run Code Online (Sandbox Code Playgroud)

这可能导致两个线程添加相同的密钥,因为它们可以在任何时候中断.

您可以使用ConcurrentDictionary.GetOrAdd代替:

private static ConcurrentDictionary<string, ISettings> _settingsDictionary = new ConcurrentDictionary<string, ISettings>();

public T Settings<T>() where T : ISettings, new() {
    var key = typeof(T).FullName;

    return _settingsDictionary.GetOrAdd(key, _settingsService.GetSettings<T>());
}
Run Code Online (Sandbox Code Playgroud)

编辑:由于您不希望_settingsService.GetSettings<T>()每次都执行,替代方案可能是:

private static IDictionary<string, ISettings> _settingsDictionary = new Dictionary<string, ISettings>();
private static object locker = new object();

public T Settings<T>() where T : ISettings, new() {
    var key = typeof(T).FullName;
    lock(locker) 
    {
        if (!_settingsDictionary.ContainsKey(key))
            _settingsDictionary[key] = _settingsService.GetSettings<T>();

        return (T)_settingsDictionary[key];
    }
}
Run Code Online (Sandbox Code Playgroud)