List和Queue使用过程中的纪录
业务需求: 发送特定的请求,根据返回的信息执行特定的事件。
目前的做法:把我的请求放入一个容器内,然后待到某一条件,就从这个容器把请求发送出去,等客户返回信息时,查询容器中对应请求中特定的事件。开始的时候我使用 List .其中遇到一些问题,纪录一下
1 namespace CollSecExp
2 {
3 class Program
4 {
5 static void Main(string[] args)
6 {
7 List<int> list = new List<int>();
8 for (int i = 0; i < 10; i++)
9 {
10 list.Add(i);
11 }
12
13 Thread t1 = new Thread(() =>
14 {
15 foreach (var item in list)
16 {
17 Console.WriteLine("t1.item:{0}", item);
18 Thread.Sleep(1000);
19 }
20 });
21 t1.Start();
22
23 Thread t2 = new Thread(() =>
24 {
25 Thread.Sleep(1000);
26 list.RemoveAt(1);
27 list.RemoveAt(3);
28 foreach (var item in list)
29 {
30 Console.WriteLine("t2.item:{0}", item);
31 }
32 });
33 t2.Start();
34 }
35 }
36 }运行会抛出InvalidOperationException异常,提示“集合已修改;可能无法执行枚举操作。”
这是因为,线程2移除index=1,3的元素导致集合被修改。使用加锁
1 namespace CollSecExp
2 {
3 class Program
4 {
5 static void Main(string[] args)
6 {
7 object sycObj = new object();
8 List<int> list = new List<int>();
9 for (int i = 0; i < 10; i++)
10 {
11 list.Add(i);
12 }
13
14 Thread t1 = new Thread(() =>
15 {
16 lock (sycObj)
17 {
18 foreach (var item in list)
19 {
20 Console.WriteLine("t1.item:{0}", item);
21 Thread.Sleep(1000);
22 }
23 }
24 });
25 t1.Start();
26
27 Thread t2 = new Thread(() =>
28 {
29 Thread.Sleep(1000);
30 lock (sycObj)
31 {
32 list.RemoveAt(1);
33 list.RemoveAt(3);
34 foreach (var item in list)
35 {
36 Console.WriteLine("t2.item:{0}", item);
37 }
38 }
39 });
40 t2.Start();
41 }
42 }
43 }加锁就可以解决了。
后来使用了想起了对于请求,我们可以使用队列,最简单的请求Queue如下
1 static void Main(string[] args)
2 {
3 int count = 0;
4 Queue<int> queue = new Queue<int>();
5 Task.Factory.StartNew(() =>
6 {
7 while (true)
8 {
9 Thread.Sleep(3000);
10 Console.WriteLine("生产的元素是: " + count);
11 queue.Enqueue(count);
12 count++;
13
14 }
15
16 });
17
18 ;
19 Task.Factory.StartNew(() =>
20 {
21 while (true)
22 {
23 if (queue.Count > 0)
24 {
25 int value = queue.Dequeue();
26 Console.WriteLine("worker1 " + ": 消费的元素是: " + value);
27 }
28 }
29
30 });
31
32 Task.Factory.StartNew(() =>
33 {
34 while (true)
35 {
36 if (queue.Count > 0)
37 {
38 int value = queue.Dequeue();
39 Console.WriteLine(Thread.CurrentThread + " : 消费的元素是: " + value);
40 }
41 }
42
43 });
44
45
46 Console.ReadKey();
47
48 }由于没有加锁或是其他机制,那么很容易出错,于是改进了版本。
1 static void Main(string[] args)
2 {
3 int count = 0;
4 var queue = new ConcurrentQueue<int>();
5 Task.Factory.StartNew(() =>
6 {
7 while (true)
8 {
9 Thread.Sleep(1000);
10 Console.WriteLine("生产的元素是: " + count);
11 queue.Enqueue(count);
12 count++;
13
14 }
15
16 });
17
18 ;
19 Task.Factory.StartNew(() =>
20 {
21 while (true)
22 {
23
24 int value;
25 if (queue.TryDequeue(out value))
26 {
27 Console.WriteLine("worker1 " + ": 消费的元素是: " + value);
28 }
29
30 }
31
32 });
33
34 Task.Factory.StartNew(() =>
35 {
36 while (true)
37 {
38 int value;
39 if (queue.TryDequeue(out value))
40 {
41 Console.WriteLine("worker2 " + " : 消费的元素是: " + value);
42 }
43 }
44
45 });
执行这段代码,可以工作,但是有点不太优雅,能不能不要去判断集合是否为空?集合当自己没有元素的时候自己Block一下可以吗?答案当然是可以的,使用BlockingCollection即可:
1 static void Main(string[] args)
2 {
3 int count = 0;
4 var queue = new BlockingCollection<int>();
5 var product = Task.Factory.StartNew(() =>
6 {
7 for (int i = 20 - 1; i >= 0; i--)
8 {
9 Console.WriteLine("生产的元素是: " + count);
10 queue.Add(count);
11 count++;
12 }
13
14 });
15
16
17 var consumer1 = Task.Factory.StartNew(() =>
18 {
19 foreach (int value in queue.GetConsumingEnumerable())
20 {
21 Console.WriteLine("worker1 " + ": 消费的元素是: " + value);
22
23 }
24
25 });
26
27 var consumer2 = Task.Factory.StartNew(() =>
28 {
29 foreach (int value in queue.GetConsumingEnumerable())
30 {
31 if (value % 2 == 0)
32 {
33 Console.WriteLine("worker2 " + " : 消费的元素是: " + value);
34 }
35 else
36 {
37 queue.Add(value);
38 }
39 }
40 });
41 Task.WaitAny(product, consumer2, consumer1);
42 Console.ReadKey();
43 }
当我需要控制Queue停止反复遍历获取queue是否存在元素时,可以使用如下方法,同时在构造方法中可以指定队列的大小
1 blockingCollection.CompleteAdding();
参考文章:
C#的变迁史 - C# 4.0 之线程安全集合篇
List和Queue使用过程中的纪录的更多相关文章
- 使用beanstalkd实现定制化持续集成过程中pipeline
持续集成是一种项目管理和流程模型,依赖于团队中各个角色的配合.各个角色的意识和配合不是一朝一夕能练就的,我们的工作只是提供一种方案和能力,这就是持续集成能力的服务化.而在做持续集成能力服务化的过程中, ...
- zabbix 3.0.3 (nginx)安装过程中的问题排错记录
特殊注明:安装zabbix 2.4.8和2.4.6遇到2个问题,如下:找了很多解决办法,实在无解,只能换版本,尝试换(2.2.2正常 | 3.0.3正常)都正常,最后决定换3.0.3 1.Error ...
- 最新cocoapods安装流程,安装过程中遇到的问题及解决方法
最近重新安装了一次cocoapods,参考的安装流程:http://blog.csdn.net/showhilllee/article/details/38398119/ 但是现在的cocoapods ...
- ios逆向过程中lldb调试技巧
在ios逆向过程中,善于运用lldb,会给逆向带来很大的方便 一般的命令: 1.image list -o -f 看看各个模块在内存中的基址 2.register read r0 读取寄存器r0的 ...
- 使用 VSTS 进行 CI 的过程中,无法识别 .NET Core 2.x 的情况处理
大概是由于 .NET Core 2.1 还没有正式发布,使用 VSTS 进行持续集成(CI)的过程中,自动 Build 的环节无法识别 .NET Core 2.1 的框架,查看日志会提示如下错误: V ...
- sharepoint环境安装过程中几点需要注意的地方
写在前面 上篇文章也说明了,在安装sharepoint环境的时候,确实吃了不少苦头,这里纪录一下安装过程中遇到的几个问题. 安装环境 windows server 2012 r2 standard x ...
- QTcpSocket使用过程中的一些问题记录
目前,在将原来C的socket通讯改为使用Qt类库QTcpSocket通讯,在修改过程中遇到不少问题,在此将问题一并记录,以备后面使用. 采用的通讯方式:QTimer定时器.QThread多线程和QT ...
- CASE:DB shutdown/open 过程中发生异常导致JOB不能自动执行
CASE:DB shutdown/open 过程中发生异常导致JOB不能自动执行 现象: 一个DB中的所有JOB在3月25日之后就不再自动运行,查询DBA_JOBS,发现LAST_DATE定格在3月2 ...
- 在对listctrl的控件进行重载的过程中,GetHeaderCtrl()返回NULL的问题
先谈谈我的问题吧! 在使用listctrl的过程中,我需要在列表头部添加checkbox,实现全选的功能. 经过网上资料的罗列,我找到了一个demo,使用的重绘的方法,在使用的过程中,我发现我的列表头 ...
随机推荐
- Spring Cloud使用总结
本文来自网易云社区,转载务必请注明出处. Spring Cloud 是spring团队推出的基于SpringBoot的分布式微服务框架,为开发者提供了在分布式系统(如配置管理.服务发现.断路器.智能路 ...
- 《Beginning Java 7》 - 7 - abstract class 抽象类 和 interface 接口
1. 抽象类: 为什么用抽象类: 一些 generic 的类本身并没有现实意义,所以不需要被实例化.比如动物,自然界没有动物这个物种,但却有无数的继承自动物的物种,那么动物本身可以是一个抽象类. 抽象 ...
- Struts2学习第4天--拦截器
第1章 Struts2_day04笔记 1.1 上次课内容回顾 l OGNL表达式 n OGNL的概述 u OGNL:对象图导航语言,是一门功能强大的表达式语言. n OGN ...
- OCP换考题了,052新考题及答案整理-第17题
17.Which two statements are true about tablespaces? A) A database can contain multiple undo tablespa ...
- jquery源码解析:jQuery延迟对象Deferred(工具方法)详解1
请先看上一课的回调对象.Deferred是通过extend添加到jQuery中的工具方法.如下所示: jQuery.extend({ Deferred: function( func ) { }, w ...
- 从零开始用 Flask 搭建一个网站(四)
前言 从零开始用 Flask 搭建一个网站(三) 介绍了网页前端与后端.前端与前端之间数据的交流.本节主要介绍一下如何应用 Flask-OAuthlib, 使用 Flask-OAuthlib 就可以轻 ...
- easyui里面的API=====》 load
在easyui里面有个API load,这个API实用性质很强,可以直接帮我加载页面的数据到想需要的相应输入框里面,但是也要注意,这些将要被填入数据的输入框里面的属性有个要求:其中输入框里面的name ...
- CF666E Forensic Examination SAM+线段树合并+前缀树倍增
$ \color{#0066ff}{ 题目描述 }$ 给你一个串\(S\)以及一个字符串数组\(T[1..m]\),\(q\)次询问,每次问\(S\)的子串\(S[p_l..p_r]\)在\(T[l. ...
- 'node' 不是内部或外部命令,也不是可运行的程序或批处理文件
状况:安装完nodejs之后,命令行输入node -v, 提示 'node' 不是内部或外部命令,也不是可运行的程序或批处理文件原因:检查环境变量没有配置正确配置环境变量: windows系统里, 需 ...
- Docker 镜像加速
通过 Docker 官方镜像加速,中国区用户能够快速访问最流行的 Docker 镜像.该镜像托管于中国大陆,本地用户现在将会享受到更快的下载速度和更强的稳定性,从而能够更敏捷地开发和交付 Docker ...