每次写博客,第一句话都是这样的:程序员很苦逼,除了会写程序,还得会写博客!当然,希望将来的一天,某位老板看到此博客,给你的程序员职工加点薪资吧!因为程序员的世界除了苦逼就是沉默。我眼中的程序员大多都不爱说话,默默承受着编程的巨大压力,除了技术上的交流外,他们不愿意也不擅长和别人交流,更不乐意任何人走进他们的内心!

最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来。我们都知道计算机技术发展日新月异,速度惊人的快,你我稍不留神,就会被慢慢淘汰!因此:每日不间断的学习是避免被淘汰的不二法宝。

当然,题外话说多了,咱进入正题!

简单的总结下对预防并发的理解:预防并发其实就是将并行执行修改为串行执行。(关于数据库并发问题大家可参考我的博客:C# 数据库并发的解决方案(通用版、EF版))

背景

C#命名空间:System.Collenctions和System.Collenctions.Generic 中提供了很多列表、集合和数组。例如:List<T>集合,数组Int[],String[] ......,Dictory<T,T>字典等等。但是这些列表、集合和数组的线程都不是安全的,不能接受并发请求。下面通过一个例子来加以说明,如下:

 class Program{private static object o = new object();private static List<Product> _Products { get; set; }/*  coder:天才卧龙  *  代码中 创建三个并发线程 来操作_Products 集合*  System.Collections.Generic.List 这个列表在多个线程访问下,不能保证是安全的线程,所以不能接受并发的请求,我们必须对ADD方法的执行进行串行化*/static void Main(string[] args){_Products = new List<Product>();/*创建任务 t1  t1 执行 数据集合添加操作*/Task t1 = Task.Factory.StartNew(() =>{AddProducts();});/*创建任务 t2  t2 执行 数据集合添加操作*/Task t2 = Task.Factory.StartNew(() =>{AddProducts();});/*创建任务 t3  t3 执行 数据集合添加操作*/Task t3 = Task.Factory.StartNew(() =>{AddProducts();});Task.WaitAll(t1, t2, t3);Console.WriteLine(_Products.Count);Console.ReadLine();}/*执行集合数据添加操作*/static void AddProducts(){Parallel.For(0, 1000, (i) =>{Product product = new Product();product.Name = "name" + i;product.Category = "Category" + i;product.SellPrice = i;_Products.Add(product);});}}class Product{public string Name { get; set; }public string Category { get; set; }public int SellPrice { get; set; }}

本例中,开辟了三个线程,通过循环向集合中添加数据,每个线程执行1000次(三个线程之间的操作是同时进行的,也是并行的),那么,理论上结果应该是3000。

上文中我们讲到: C#命名空间:System.Collenctions和System.Collenctions.Generic 下的列表,数组,集合并不能保证线程安全,并不能防止并发的发生。

本例运行的结果也证明了上述结论的正确性,其结果如下:

由此可见:C#命名空间:System.Collenctions和System.Collenctions.Generic 下的列表,数组,集合确实不能保证线程安全,确实不能预防并发。那么我们应当怎么解决上述问题呢?

还好,自C#2.0以来,LOCK是一直存在的。使用LOCK(互斥锁)是可以做到防止并发的,示例代码如下:

 class Program{private static object o = new object();private static List<Product> _Products { get; set; }/*  coder:天才卧龙  *  代码中 创建三个并发线程 来操作_Products 集合*  System.Collections.Generic.List 这个列表在多个线程访问下,不能保证是安全的线程,所以不能接受并发的请求,我们必须对ADD方法的执行进行串行化*/static void Main(string[] args){_Products = new List<Product>();/*创建任务 t1  t1 执行 数据集合添加操作*/Task t1 = Task.Factory.StartNew(() =>{AddProducts();});/*创建任务 t2  t2 执行 数据集合添加操作*/Task t2 = Task.Factory.StartNew(() =>{AddProducts();});/*创建任务 t3  t3 执行 数据集合添加操作*/Task t3 = Task.Factory.StartNew(() =>{AddProducts();});Task.WaitAll(t1, t2, t3);Console.WriteLine(_Products.Count);Console.ReadLine();}/*执行集合数据添加操作*/static void AddProducts(){Parallel.For(0, 1000, (i) =>{lock (o){Product product = new Product();product.Name = "name" + i;product.Category = "Category" + i;product.SellPrice = i;_Products.Add(product);}});}}class Product{public string Name { get; set; }public string Category { get; set; }public int SellPrice { get; set; }}

引入了Lock,运行结果也正常了,如下:

但是锁的引入,带来了一定的开销和性能的损耗,并降低了程序的扩展性,而且还会有死锁的发生(虽说概率不大,但也不能不防啊),因此:使用LOCK进行并发编程显然不太适用。

还好,微软一直在更新自己的东西:

.NET Framework 4提供了新的线程安全和扩展的并发集合,它们能够解决潜在的死锁问题和竞争条件问题,因此在很多复杂的情形下它们能够使得并行代码更容易编写,这些集合尽可能减少使用锁的次数,从而使得在大部分情形下能够优化为最佳性能,不会产生不必要的同步开销。

需要注意的是:在串行代码中使用并发集合是没有意义的,因为它们会增加无谓的开销。

在.NET Framework4.0以后的版本中提供了命名空间:System.Collections.Concurrent 来解决线程安全问题,通过这个命名空间,能访问以下为并发做好了准备的集合。

   1.BlockingCollection 与经典的阻塞队列数据结构类似,能够适用于多个任务添加和删除数据,提供阻塞和限界能力。

   2.ConcurrentBag 提供对象的线程安全的无序集合

   3.ConcurrentDictionary  提供可有多个线程同时访问的键值对的线程安全集合

   4.ConcurrentQueue   提供线程安全的先进先出集合

   5.ConcurrentStack   提供线程安全的后进先出集合

这些集合通过使用比较并交换和内存屏障等技术,避免使用典型的互斥重量级的锁,从而保证线程安全和性能。

   ConcurrentQueue 

ConcurrentQueue 是完全无锁的,能够支持并发的添加元素,先进先出。下面贴代码,详解见注释:

C# 集合-并发处理相关推荐

  1. C# .net 集合-并发处理之文件读写处理

    //读写锁,当资源处于写入模式时,其他线程写入需要等待本次写入结束之后才能继续写入static ReaderWriterLockSlim LogWriteLock = new ReaderWriter ...

  2. .NET的ConcurrentDictionary,线程安全集合类

    ConcurrentDictionary 是.NET 4.0里面新增的号称线程安全的集合类. 那么自然,我们会预期ConcurrentDictionary 中的代码是线程安全的(至少几个关键方法是线程 ...

  3. Java把一个大集合拆分成多个小集合,可以利用多线程提升并发处理效率

    场景: 在开发中,如果一个集合中的数据量特别大,那么对这个集合进行循环处理业务可能就会比较耗时,为了提升效率,可以考虑把大集合拆分成多个小集合,然后用多线程对拆分后的多个小集合进行处理 拆分: 1.拆 ...

  4. 高并发大流量专题---8、动态语言的并发处理

    高并发大流量专题---8.动态语言的并发处理 一.总结 一句话总结: 和本科毕业论文连起来了:基于消息中间件Rocket MQ的研究:用于并发处理的消息队列 1.什么是进程.线程.协程? 进程(Pro ...

  5. LR中如何添加事务,参数化,检查点,集合点,思考时间等

    1.事务 事务的定义 添加事务(Transaction) 为了衡量某个action的性能,需要在action的开始和结束位置插入这 样一个范围,这就定义了一个事务 LR运行到该事务的开始点时,LR就会 ...

  6. 最常问的MySQL面试题集合

    除了基础题部分,本文还收集整理的MySQL面试题还包括如下知识点或题型: MySQL高性能索引 SQL语句 MySQL查询优化 MySQL高扩展高可用 MySQL安全性 问题1:char.varcha ...

  7. 【重难点】【Java集合 01】HashMap 和 ConcurrentHashMap

    [重难点][Java集合 01]HashMap 文章目录 [重难点][Java集合 01]HashMap 一.HashMap 1.概述 2.JDK 1.8 中的变化 3.链表转换为红黑树 4.扩容问题 ...

  8. oracle 042 第八章:管理数据和并发处理

    SQL INSERT 一次创建一行. INSERTINTOemployees VALUES (9999,'Bob','Builder','bob@abc.net',NULL,SYSDATE, 'IT_ ...

  9. 高并发处理之商品详情页

    首页 博客 专栏·视频 下载 论坛 问答 代码 直播 能力认证 高校 会员中心 收藏 动态 消息 创作中心 高并发处理之商品详情页 卜大伟 2019-01-18 11:13:47  2488  收藏  ...

最新文章

  1. python画圣诞树代码-圣诞节!教你用Python画棵圣诞树
  2. 打包java程序生成exe
  3. 【已解决】如何干干净净的卸载MySQL数据库
  4. 服务器打不QQ显示00001,QQ登录超时00001怎么处理?
  5. jQuery Mobile 1.1 : 更流畅,更快捷,更实用
  6. 最小生成树的Prime算法的思想
  7. python 如何定义一个变量为数字_python – 如何在Pandas / Numpy中确定列/变量是否为数字?...
  8. 系统调用功能模块的初始化
  9. windows下PostgreSQL 安装与配置
  10. 只需三种手段,将传统的网站的性能提高 24%!
  11. 1027. 打印沙漏(20)-PAT乙级真题
  12. 七牛Android播放器V1版本开发文档
  13. Quartz 知识点汇总
  14. 最全PLC输入输出各种回路接线
  15. 可视化神器Plotly玩转桑基图
  16. STM32F4的DMA
  17. java wps 二次开发,Wps二次开发(POI)
  18. 常见损失函数 损失函数选择方法
  19. 音视频开发系列(15):视频与音频同步
  20. 人力资源管理专业知识与实务(初级)【9】

热门文章

  1. 【基金申请】立项依据必要性撰写案例 (及申请书撰写自查表)
  2. 【游戏开发】多人游戏网络同步相关技术(延迟处理)
  3. 数学图形(1.14) 十字星形线
  4. NPL系列之应用介绍和技术需求(一)
  5. linux线程调用完类就退出,linux下 c中怎么让才能安全关闭线程 和 linux线程退出时执行的程序(线程清理处理程序)简单例子...
  6. 3主3从redis集群扩缩容配置案例说明
  7. bs4主要知识点介绍及实例解析---利用bs4爬取伯乐在线(分别存储在数据库和xls表中)
  8. 使用Business Events和Business Monitor对传感器数据进行智能分析
  9. 4.4 like通配符关键字过滤查询数据
  10. 如何可以把模糊的照片变得高清?