.NET 4 开始,在System.Collection.Concurrent中提供了几个线程安全的集合类。线程安全的集合可防止多个线程以相互冲突的方式访问集合。
  为了对集合进行线程安全的访问,定义了IProducerConsumerCollection<T>接口。这个接口中最重要的方法是TryAdd()和TryTake()。TryAdd()方法尝试给集合添加一项,但如果集合禁止添加项,这个操作就可能失败。TryAdd()方法返回一个布尔值,以说明操作成功还是失败。TryTake()同样,在成功时返回集合中的项。
    *ConcurrentQueue<T>————这个集合类用一种免锁定的算法实现,使用在内部合并到一个链表中的32项数组。该类有Enqueue(),TryDequeue()和TryPeek()方法。因为这个类实现了              IProducerConsumerCollection<T>接口,所以TryAdd()和TryTake()方法仅调用Enqueue和TryDequeue方法。
    *ConcurrentStack<T>————类似于ConcurrentQueue<T>。该类定义了Push(),PushRange(),TryPeek(),TryPop()和TryPopRange()方法。在内部这个类使用其元素的链表。
    *ConcurrentBag<T>————该类没有定义添加或提取项的任何顺序。这个类使用一个线程映射到内部使用的数组上的概念,因此尝试减少锁定。方法:Add(),TryPeek(),TryTake()。
    *ConcurrentDictionary<TKey,TValue>————这是一个线程安全的键值集合。TryAdd(),TryGetValue(),TryRemove()和TryUpdate()方法以非阻塞的方式访问成员。因为元素基于键和值,所以  ConcurrentDictionary<TKey,TValue>没有实现IProducerConsumerCollection<T>接口。
    *BlockingCollection<T>————这个集合在可以添加或提取元素之前,会阻塞线程并一直等待。BlockingCollection<T>集合提供了一个接口,以使用Add()和Take()方法来删除和添加元素。这些方法会阻塞线程。Add()方法有一个重载版本,其中可以给该重载版本传递一个CancellationToken令牌。这个令牌允许取消被阻塞的调用。如果不希望无限的等待下去,且不希望从外部取消调用,就可以使用TryAdd()和TryTake()方法,在这些方法中,也可以指定一个超时值。
  BlockingCollection<T>是对实现了 IProducerConsumerCollection<T>接口的任意类的修饰器,它默认使用ConcurrentQueue<T>类。还可以给构造函数传递任何实现了 IProducerConsumerCollection<T>接口的类。

  下面使用一个例子演示BlockingCollection<T>的使用,一个任务向一个集合写入,同时另一个任务从这个集合读取。

    static void Main(string[] args)
{
StartPipeline();
Console.ReadLine();
} private static async void StartPipeline()
{
//存储文件名
var fileNames = new BlockingCollection<string>();
//存储文件的每一行内容
var lines = new BlockingCollection<string>();
//存储每一行的每个单词,单词为键,单词个数为值
var words = new ConcurrentDictionary<string, int>();
//存储words信息
var items = new BlockingCollection<Info>();
var coloredItems = new BlockingCollection<Info>(); Task t1 = PipelineStages.ReadFilenamesAsync(@"../../..", fileNames);
ConsoleHelper.WriteLine("started stage 1");
Task t2 = PipelineStages.LoadContentAsync(fileNames, lines);
ConsoleHelper.WriteLine("started stage 2");
Task t3 = PipelineStages.ProcessContentAsync(lines, words);
await Task.WhenAll(t1, t2, t3);
ConsoleHelper.WriteLine("stages 1, 2, 3 completed"); //当上面三个任务完成时,才执行下面的任务
Task t4 = PipelineStages.TransferContentAsync(words, items);
Task t5 = PipelineStages.AddColorAsync(items, coloredItems);
Task t6 = PipelineStages.ShowContentAsync(coloredItems);
ConsoleHelper.WriteLine("stages 4, 5, 6 started"); await Task.WhenAll(t4, t5, t6); ConsoleHelper.WriteLine("all stages finished");
} public static class PipelineStages
{
public static Task ReadFilenamesAsync(string path, BlockingCollection<string> output)
{
return Task.Run(() =>
{
foreach (string filename in Directory.EnumerateFiles(path, "*.cs", SearchOption.AllDirectories))
{
output.Add(filename);
ConsoleHelper.WriteLine(string.Format("stage 1: added {0}", filename));
}
//调用CompleteAdding,通知所有读取器不应再等待集合中的任何额外项
//如果不调用该方法,读取器会在foreach循环中等待更多的项被添加
output.CompleteAdding();
});
} public static async Task LoadContentAsync(BlockingCollection<string> input, BlockingCollection<string> output)
{
//使用读取器读取集合时,需要使用GetConsumingEnumerable获取阻塞集合的枚举器,
//如果直接使用input迭代集合,这只会迭代当前状态的集合,不会迭代以后添加的项
foreach (var filename in input.GetConsumingEnumerable())
{
using (FileStream stream = File.OpenRead(filename))
{
var reader = new StreamReader(stream);
string line = null;
while ((line = await reader.ReadLineAsync()) != null)
{
output.Add(line);
ConsoleHelper.WriteLine(string.Format("stage 2: added {0}", line));
}
}
}
output.CompleteAdding();
} public static Task ProcessContentAsync(BlockingCollection<string> input, ConcurrentDictionary<string, int> output)
{
return Task.Run(() =>
{
foreach (var line in input.GetConsumingEnumerable())
{
string[] words = line.Split(' ', ';', '\t', '{', '}', '(', ')', ':', ',', '"');
foreach (var word in words.Where(w => !string.IsNullOrEmpty(w)))
{
//这里使用了字典的一个扩展方法
output.AddOrIncrementValue(word);
ConsoleHelper.WriteLine(string.Format("stage 3: added {0}", word));
}
}
});
} public static Task TransferContentAsync(ConcurrentDictionary<string, int> input, BlockingCollection<Info> output)
{
return Task.Run(() =>
{
foreach (var word in input.Keys)
{
int value;
if (input.TryGetValue(word, out value))
{
var info = new Info { Word = word, Count = value };
output.Add(info);
ConsoleHelper.WriteLine(string.Format("stage 4: added {0}", info));
}
}
output.CompleteAdding();
});
} public static Task AddColorAsync(BlockingCollection<Info> input, BlockingCollection<Info> output)
{
return Task.Run(() =>
{
foreach (var item in input.GetConsumingEnumerable())
{
if (item.Count > )
{
item.Color = "Red";
}
else if (item.Count > )
{
item.Color = "Yellow";
}
else
{
item.Color = "Green";
}
output.Add(item);
ConsoleHelper.WriteLine(string.Format("stage 5: added color {1} to {0}", item, item.Color));
}
output.CompleteAdding();
});
} public static Task ShowContentAsync(BlockingCollection<Info> input)
{
return Task.Run(() =>
{
foreach (var item in input.GetConsumingEnumerable())
{
ConsoleHelper.WriteLine(string.Format("stage 6: {0}", item), item.Color);
}
});
}
} //创建一个字典的扩展方法
public static class ConcurrentDictionaryExtension
{
public static void AddOrIncrementValue(this ConcurrentDictionary<string, int> dict, string key)
{
bool success = false;
while (!success)
{
int value;
if (dict.TryGetValue(key, out value))
{
if (dict.TryUpdate(key, value + , value))
{
success = true;
}
}
else
{
if (dict.TryAdd(key, ))
{
success = true;
}
}
}
}
}

这里使用了一个管道模型的编程模式,上面的添加内容,下面处理内容
   

C#集合之并发集合的更多相关文章

  1. Java多线程之同步集合和并发集合

    Java多线程之同步集合和并发集合 不管是同步集合还是并发集合他们都支持线程安全,他们之间主要的区别体现在性能和可扩展性,还有他们如何实现的线程安全. 同步集合类 Hashtable Vector 同 ...

  2. Java 中的同步集合与并发集合有什么区别?

    同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发 集合的可扩展性更高.在 Java1.5 之前程序员们只有同步集合来用且在多线程并发 的时候会导致争用,阻碍了系统的扩展性.Jav ...

  3. java多线程中并发集合和同步集合有哪些?区别是什么?

    java多线程中并发集合和同步集合有哪些? hashmap 是非同步的,故在多线程中是线程不安全的,不过也可以使用 同步类来进行包装: 包装类Collections.synchronizedMap() ...

  4. .Net多线程编程—并发集合

    并发集合 1 为什么使用并发集合? 原因主要有以下几点: System.Collections和System.Collections.Generic名称空间中所提供的经典列表.集合和数组都不是线程安全 ...

  5. C#并行编程-并发集合

    菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 ...

  6. 《C#并行编程高级教程》第4章 并发集合 笔记

    这一章主要介绍了System.Collections.Concurrent下的几个类. ConcurrentQueue<T> 并发队列.完全无锁,使用CAS(compare-and-swa ...

  7. Java多线程 阻塞队列和并发集合

    转载:大关的博客 Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容.在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃.Java为多线程专门提供了特有的 ...

  8. java 多线程 同步 观察者 并发集合的一个例子

    //第一版 package com.hra.riskprice; import com.hra.riskprice.SysEnum.Factor_Type; import org.springfram ...

  9. 转载 .Net多线程编程—并发集合 https://www.cnblogs.com/hdwgxz/p/6258014.html

    集合 1 为什么使用并发集合? 原因主要有以下几点: System.Collections和System.Collections.Generic名称空间中所提供的经典列表.集合和数组都不是线程安全的, ...

随机推荐

  1. 【Yii系列】Yii2.0基础框架

    缘起 因为一个月的短暂停留,我在给朋友搞事情,所以Yii系列的文章耽搁了很长时间,现在又重拾当时的知识,给大伙好好撸下这一系列的博客 提起Yii,虽然是国外的开发者搞的,但是它的作者是华人,这才是让我 ...

  2. Node.js服务端框架谁才是你的真爱

    1. Express 背景: Express, 疯一般快速(而简洁)的服务端JavaScript Web开发框架,基于Node.js和V8 JavaScript引擎. Express 是一个基于 No ...

  3. centos6.5 源码安装 gtk 环境

    解决 No package 'gtk+-2.0′ found问题方法:yum install libgnomeui-devel 执行了上面的,下面的就可以放弃了,yum 大法好 首先 yum 安装下面 ...

  4. CodeFirst的一些操作!!

    CodeFirst的一些操作!! 转载 2016-08-05 21:03:32 1 首先是codefirst怎么做,这个首先肯定要引入EntityFramework,然后在model中创建实体类,例如 ...

  5. Vijos1523贪吃的九头龙【树形DP】

    贪吃的九头龙 传说中的九头龙是一种特别贪吃的动物.虽然名字叫"九头龙",但这只是说它出生的时候有九个头,而在成长的过程中,它有时会长出很多的新头,头的总数会远大于九,当然也会有旧头 ...

  6. 使用composer下拉组件失败,出现killed解决办法

    做项目时下载composer组件,出现killed提示,如图 一般是因为内存太小,将虚拟机内存设置大一点即可,在虚拟机关机的时候设置 下载成功

  7. ElasticSearch查询 第五篇:布尔查询

    布尔查询是最常用的组合查询,不仅将多个查询条件组合在一起,并且将查询的结果和结果的评分组合在一起.当查询条件是多个表达式的组合时,布尔查询非常有用,实际上,布尔查询把多个子查询组合(combine)成 ...

  8. yii2-验证规则,rules,判断条件

    yii2模型的验证规则,简单的使用我就不详细说了,想看的可以去看官网教程http://www.yiichina.com/doc/guide/2.0/structure-models#validatio ...

  9. 1134: 零起点学算法41——多组测试数据(a+b)III

    1134: 零起点学算法41--多组测试数据(a+b)III Time Limit: 1 Sec  Memory Limit: 64 MB   64bit IO Format: %lldSubmitt ...

  10. SQL编程的一些良好好习惯

    |转载自:cnblog |原文链接:http://www.cnblogs.com/MR_ke/archive/2011/05/29/2062085.html 我们做软件开发的,大部分人都离不开跟数据库 ...