ConcurrentDictionary中的AddOrUpdate线程是否安全?

时间:2016-08-26 00:40:04

标签: c# multithreading

我尝试在ConcurrentDictionary中使用AddOrUpdate方法。

来自"备注"本页https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx部分。它说

  

"但是,这些方法的代表在锁之外调用,以避免在锁定下执行未知代码时可能出现的问题。因此,这些代理执行的代码不受操作原子性的影响。"

所以我不确定它是否是线程安全的。我有一种情况,如果找不到密钥,则值为1,否则将值增加1。

我写下了函数

    private static void AddOrUpdate(ConcurrentDictionary<string, int> map)
    {
        Random r = new Random();
        Thread.Sleep(r.Next(10));
        map.AddOrUpdate(Key, 1, (key, value) => value + 1);
    }

    public static void TestThreadSafe(ConcurrentDictionary<string, int> map)
    {
        Thread[] threads = new Thread[Size];
        for (int i = 0; i < Size; ++i)
        {
            threads[i] = new Thread(() => AddOrUpdate(map));
        }

        foreach (var thread in threads)
        {
            thread.Start();
        }
    }

创建了大约300,000个线程并并行运行它们。结果总是300,000。

上面的方法线程是否安全? AddOrUpdate何时不是线程安全的?

1 个答案:

答案 0 :(得分:5)

在您的使用中是线程安全的。传递给AddOrUpdate的委托具有副作用时,它变得不是线程安全的,因为对于相同的键和现有值,这些副作用可能会被执行两次。

例如:

private static void AddOrUpdate(ConcurrentDictionary<string, int> map)
    {
        Random r = new Random();
        Thread.Sleep(r.Next(10));
        map.AddOrUpdate(Key, 1, (key, value) => { Console.WriteLine(key + ": " + value); return value + 1; });
    }

可以多次打印相同的键+值。

有时候ConcurrentDictionary可以在多个线程上执行这些方法,然后获取结果值并输入锁以尝试应用它。其中一个线程将成功,另一个线程将进入锁定,看到值已经更改,因为它读取它,并再次尝试委托。