对ConcurrentDictionary的线程安全更改

本文关键字:安全 线程 ConcurrentDictionary | 更新日期: 2023-09-27 18:08:15

我在Parallel.ForEach循环中填充ConcurrentDictionary:

var result = new ConcurrentDictionary<int, ItemCollection>();
Parallel.ForEach(allRoutes, route => 
{
    // Some heavy operations
    lock(result)
    {
        if (!result.ContainsKey(someKey))
        {
            result[someKey] = new ItemCollection();
        }
        result[someKey].Add(newItem);
    }
}

如何在不使用lock语句的情况下以线程安全的方式执行最后的步骤?

EDIT:假设ItemCollection是线程安全的

对ConcurrentDictionary的线程安全更改

我认为你想要GetOrAdd,它被明确地设计为要么获取一个现有的项目,要么添加一个新的,如果没有给定键的条目。

var collection = result.GetOrAdd(someKey, _ => new ItemCollection());
collection.Add(newItem);

如问题注释中所述,这假设ItemCollection是线程安全的。

您需要使用GetOrAdd方法。

var result = new ConcurrentDictionary<int, ItemCollection>();
int someKey = ...;
var newItem = ...;
ItemCollection collection = result.GetOrAdd(someKey, _ => new ItemCollection());
collection.Add(newItem);

假设ItemCollection.Add不是线程安全的,您需要一个锁,但是您可以减小临界区域的大小。

var collection = result.GetOrAdd(someKey, k => new ItemCollection());
lock(collection)
    collection.Add(...);

更新:因为它似乎是线程安全的,你根本不需要锁

var collection = result.GetOrAdd(someKey, k => new ItemCollection());
collection.Add(...);