C#线程安全集合类说明(3): ConcurrentDictionary<TKey,TValue>字典

线程安全的集合所在的命名空间 using System.Collections.Concurrent;

Concurrent意思是并发的,并行的。反义是sequential(顺序的),线程安全的意思就是多线程中的同步锁(Lock)

ConcurrentDictionary<TKey,TValue> 类

表示可由多个线程同时访问的键/值对的线程安全集合。

参考微软官方文档:

https://docs.microsoft.com/zh-cn/dotnet/api/system.collections.concurrent?view=netframework-4.5

参考源代码(类BlockingCollection<T>)

https://referencesource.microsoft.com/#mscorlib/system/Collections/Concurrent/ConcurrentDictionary.cs,2e5ef5704344a309

与 System.Collections.Generic.Dictionary<TKey,TValue> 类一样, ConcurrentDictionary<TKey,TValue> 实现 IDictionary<TKey,TValue> 接口。 此外, ConcurrentDictionary<TKey,TValue> 提供了几种在字典中添加或更新键/值对的方法,如下表所述。

注解
任务方法使用注意事项
如果字典中不存在新项,则将其添加到字典中TryAdd如果字典中当前不存在该键,则此方法将添加指定的键/值对。 方法返回 true 或, false 具体取决于是否已添加新对。
更新字典中现有键的值(如果该注册表项具有特定值)TryUpdate此方法检查键是否具有指定的值,如果它存在,则使用新值更新该键。 它与 CompareExchange 方法类似,只是它用于字典元素。
无条件地将键/值对存储在字典中,并覆盖已存在的键的值索引器的 setter: dictionary[key] = newValue 
将键/值对添加到字典中,或者如果该键已存在,则根据键的现有值更新该键的值AddOrUpdate(TKey, Func<TKey,TValue>, Func<TKey,TValue,TValue>)

- 或 -

AddOrUpdate(TKey, TValue, Func<TKey,TValue,TValue>)
AddOrUpdate(TKey, Func<TKey,TValue>, Func<TKey,TValue,TValue>) 接受密钥和两个委托。 如果字典中不存在该键,则使用第一个委托;它接受键并返回应为该项添加的值。 如果该键存在,它将使用第二个委托;它接受键及其当前值,并返回应为密钥设置的新值。

AddOrUpdate(TKey, TValue, Func<TKey,TValue,TValue>) 接受键、要添加的值和更新委托。 这与上一个重载相同,不同之处在于它不使用委托来添加密钥。
获取字典中的键的值,将值添加到字典中,如果键不存在,则返回它GetOrAdd(TKey, TValue)

- 或 -

GetOrAdd(TKey, Func<TKey,TValue>)
这些重载为字典中的键/值对提供延迟初始化,仅在不存在时才添加值。

GetOrAdd(TKey, TValue) 如果键不存在,则采用要添加的值。

GetOrAdd(TKey, Func<TKey,TValue>) 如果键不存在,则使用将生成值的委托。

所有这些操作都是原子操作,对类的所有其他操作都是线程安全的 ConcurrentDictionary<TKey,TValue> 。 唯一的例外是接受委托的方法,即 AddOrUpdate 和 GetOrAdd 。 对于字典的修改和写入操作, ConcurrentDictionary<TKey,TValue> 使用细粒度锁定以确保线程安全。 对字典进行 (读取操作时,将以无锁方式执行。 ) 不过,这些方法的委托在锁的外部调用,以避免在锁定下执行未知代码导致的问题。 因此,这些委托执行的代码不服从操作的原子性。

测试程序:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadSafeCollectionDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            int initialCapacity = 16;
            int concurrencyLevel = Environment.ProcessorCount * 2;

            ConcurrentDictionary<int, string> cd = new ConcurrentDictionary<int, string>(concurrencyLevel, initialCapacity);
            Console.WriteLine($"当前字典元素个数:【{cd.Count}】,是否为空【{cd.IsEmpty}】");
            Task taskAdd = Task.Factory.StartNew(() => 
            {
                bool result = cd.TryAdd(1, "北洛");
                Console.WriteLine($"添加键【1】-值【北洛】的结果:【{result}】");
                result = cd.TryAdd(3, "玄戈");
                Console.WriteLine($"添加键【3】-值【玄戈】的结果:【{result}】");
                result = cd.TryAdd(1, "巫炤");
                Console.WriteLine($"添加键【1】-值【巫炤】的结果:【{result}】");
            });
            Task taskUpdate = Task.Run(() => 
            {
                cd.AddOrUpdate(4, "云无月", (key, val) => "嫘祖");
                Console.WriteLine($"key:【4】,value:【{cd[4]}】");
                cd.AddOrUpdate(4, "云无月", (key, val) => "嫘祖");
                Console.WriteLine($"key:【4】,value:【{cd[4]}】");
                for (int i = 2; i <= initialCapacity + 1; i++)
                {
                    string val = "古剑" + i;
                    bool result = cd.TryAdd(i, val);
                    Console.WriteLine($"添加键【{i}】-值【{val}】的操作结果【{result}】");
                }
            });
            Console.WriteLine($"获取或者添加键【28】{cd.GetOrAdd(28, "川大肥")}");
            Task.WaitAll(taskAdd, taskUpdate);
            Console.WriteLine($"获取或者添加键【10】,如果键存在则获取。{cd.GetOrAdd(10, "更新")}");
            Console.WriteLine();
            Console.WriteLine("......现在测试同时移除元素功能......");
            Task taskRemove1 = Task.Run(() =>
            {
                string val;
                bool result;
                foreach (int key in cd.Keys)
                {
                    result = cd.TryRemove(key, out val);
                    Console.WriteLine($"线程【{Thread.CurrentThread.ManagedThreadId}】:尝试移除键【{key}】-值【{val}】,移除结果【{result}】");
                }
            });
            Task taskRemove2 = Task.Run(() =>
            {
                string val;
                bool result;
                foreach (int key in cd.Keys)
                {
                    result = cd.TryRemove(key, out val);
                    Console.WriteLine($"线程【{Thread.CurrentThread.ManagedThreadId}】:尝试移除键【{key}】-值【{val}】,移除结果【{result}】");
                }
            });
            Task.WhenAll(taskRemove1, taskRemove2);
            Console.ReadLine();
        }      

    }
}
 

运行结果:

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
C# 中将字典 `Dictionary<TKey, TValue>` 中的 `TValue` 变成泛型 `T`,可以使用泛型类和泛型方法来实现。 下面是一个示例代码: ```csharp using System; using System.Collections.Generic; class Program { static void Main() { // 创建一个字典,键的类型为字符串,值的类型为整数 Dictionary<string, int> myDict = new Dictionary<string, int>(); // 添加元素到字典中 myDict.Add("apple", 1); myDict.Add("banana", 2); myDict.Add("cherry", 3); // 将字典中的值类型转换成泛型 T Dictionary<string, T> ConvertDict<T>(Dictionary<string, T> dict, Func<int, T> converter) { Dictionary<string, T> newDict = new Dictionary<string, T>(); foreach (KeyValuePair<string, int> kvp in dict) { newDict.Add(kvp.Key, converter(kvp.Value)); } return newDict; } // 定义一个委托,将整数类型转换成泛型类型 T Func<int, T> converter = x => (T)(object)x; // 调用泛型方法,将字典中的值类型转换成泛型 T Dictionary<string, T> newDict = ConvertDict(myDict, converter); // 遍历新的字典中的元素 foreach (KeyValuePair<string, T> kvp in newDict) { Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value); } } } ``` 上述代码中,我们首先创建了一个字典 `myDict`,键的类型为字符串,值的类型为整数。然后定义了一个泛型方法 `ConvertDict<T>`,该方法接受一个字典和一个将整数类型转换成泛型类型 `T` 的委托。在方法中,我们遍历字典中的元素,将值类型从整数转换成泛型类型 `T`,并创建一个新的字典。最后返回新的字典。 接下来,我们定义一个将整数类型转换成泛型类型 `T` 的委托,然后调用泛型方法 `ConvertDict<T>`,将字典 `myDict` 中的值类型从整数转换成泛型类型 `T`,并将结果保存到一个新的字典 `newDict` 中。最后,我们遍历新的字典 `newDict` 中的元素,输出每个键值对的键和值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斯内科

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值