欢迎光临
我的个人博客网站

.Net 线程安全集合

.Net 提供了基于生产-消费模式的集合类,这些集合对多线程访问安全,定义在System.Collections.Concurrent名称空间中。这个名称空间中包括基础接口IProduceConsumerCollection,这个接口定义了线程安全集合的基本操作。这个名称空间中还包括常用的集合:

  • BlockingCollection
  • ConcurrentBag
  • ConcurentDictionary<TKey,TValue>
  • ConcurrentQueue
  • ConcurentStack

在使用生产-消费模式时,我们经常使用两个线程,在一个线程向集合添加数据,在另一个线程从集合中提取数据进行处理。我们可以使用实现IProduceConsumerCollection接口的集合,比如ConcurrentQueue等等。通常将从集合取数据的代码放在一个无尽循环中,如果集合中没有数据就继续循环。很多情况下,我们希望如果集合中没有数据,这个线程阻塞等待,直到有数据时再继续。这时我们可以使用BlockingCollection,这个集合提供了Add(添加数据)和Take(阻塞获取数据)方法。

下面是BlockingCollection的示例。这个集合类的Take方法可以从集合中获取并去掉一个对象,当集合为空时,可以使线程处于阻塞状态。

Console.WriteLine("--------------------------------"); Console.WriteLine("测试一个线程向集合添加数据,另一个线程读取数据,请输入人名,输入exit退出"); BlockingCollection<string> names=new BlockingCollection<string>();  Task.Run(() => {     while (true)     {         var name = names.Take();         Console.WriteLine("你好,"+name);     }  });  var name = Console.ReadLine(); while (name!="exit") {     if(!string.IsNullOrEmpty(name))   names.Add(name);     name = Console.ReadLine(); } 

BlockingCollection的另一个功能是可以封装其它的IProduceConsumerCollection集合,实现不同的添加和获取顺序,比如,如果在构造函数中传入ConcurrentQueue,添加和获取就与队列相同——“先进先出”,如果传入ConcurrentStack,顺序就与堆栈相同——“先进后出”,下面是示例代码:

using System.Collections.Concurrent;  Console.WriteLine("--------------------------------"); Console.WriteLine("测试BlockingCollection 和 ConcurrentQueue");  var queue = new ConcurrentQueue<string>(); var blockqueue= new BlockingCollection<string>(queue, 100);  Console.WriteLine("加入name1"); blockqueue.Add("name1"); Console.WriteLine("加入name2"); blockqueue.Add("name2"); Console.WriteLine("加入name3"); blockqueue.Add("name3");  Console.WriteLine(blockqueue.Take()); Console.WriteLine(blockqueue.Take()); Console.WriteLine(blockqueue.Take());  Console.WriteLine("--------------------------------"); Console.WriteLine("测试BlockingCollection 和 ConcurrentStack");  var cq = new ConcurrentStack<string>(); var bc = new BlockingCollection<string>(cq, 100);  Console.WriteLine("加入name1"); bc.Add("name1"); Console.WriteLine("加入name2"); bc.Add("name2"); Console.WriteLine("加入name3"); bc.Add("name3");  Console.WriteLine(bc.Take()); Console.WriteLine(bc.Take()); Console.WriteLine(bc.Take()); 

ConcurrentBag需要特别说明一下,在“纯生产-消费”场景中(一个线程要么向集合添加项目,要么从集合中获取项目,但不能即添加又获取),ConcurrentBag性能要比其他类型的集合慢,但在“混合生产-消费”场景中(一个线程即可以向集合添加项目,也可以获取项目),ConcurrentBag的性能要比其它类型的集合快。

赞(0) 打赏
未经允许不得转载:张拓的天空 » .Net 线程安全集合
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

专业的IT技术经验分享 更专业 更方便

联系我们本站主机

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏