.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的性能要比其它类型的集合快。

最新文章

  1. mysql中的行转列
  2. Markdown:认识&amp;入门
  3. what&#39;s the CRSF ??
  4. sql 、linq、lambda 查询语句的区别
  5. JMeter使用记录1 -- JDBC測试
  6. poj 2240 Arbitrage (Floyd)
  7. ARM汇编指令(未完待续)
  8. C#生成缩略图的方法
  9. laravel安装excel功能
  10. POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)
  11. javascript之事件处理
  12. centos 7 进入图形界面
  13. Linux性能监控分析命令(一)—vmstat命令详解
  14. python装饰器(新年第一写)
  15. html5-块元素和内联元素
  16. MyEclipse如何配置Struts2源码的框架压缩包
  17. (转) AdversarialNetsPapers
  18. java Socket和ServerSocket多线程编程
  19. PHP 导出简单文本内容(word txt等)
  20. [转]android ANR产生原因和解决办法

热门文章

  1. VUE3 之 template 语法
  2. UIWindow介绍
  3. ubuntu 10.04安装和配置Samba
  4. Windows异常分发
  5. 对Spring IOC容器的思考
  6. mysql联合索引阻碍修改列数据类型:BLOB/TEXT column &#39;name&#39; used in key specification without a key length
  7. java 多线程Thread 子类 定时器Timer
  8. Sort 多列正排序,倒排序
  9. MySQLs数据库建外键时自动跑到缩影处,真奇怪
  10. c++ vector释放概述