网上关于List的线程安全问题将的很少,所以自己实验了一把,发现确实是线程不安全的.所以当你在进行多线程编程中使用了共享的List集合,必须对其进行线程安全处理.

List的Add方法是线程不安全的,List的源码中的Add方法,使用了每次当当前的元素达到上限,通过创建一个新的数组实例,并给长度翻倍的操作.如果单线程操作不会有问题,直接扩容,然后继续往里面加值。下面是List的Add方法和核心逻辑.

也就是说,当多个线程同时添加元素,且刚好它们都执行到了扩容这个阶段,当一个线程扩大了这个数组的长度,且进行了+1操作后,另外一个线程刚好也在执行扩容的操作,这个时候它给Capacity的值设为2048,但是另外一个线程已经将this._size设为2049了,所以这个时候就报异常了.当然不止这一个问题,还有Copy的时候也会出问题,如果里面的元素过多,另外一个线程拿到空值的几率很大.

代码重现:

    class Program{static List<long> list = new List<long>();static void Main(string[] args){var t = Task.Run(() =>{var tf = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.AttachedToParent);var childTasks = new Task[]{tf.StartNew(()=>Task_0()),tf.StartNew(()=>Task_1()),tf.StartNew(()=>Task_2())};var tfTask=tf.ContinueWhenAll(childTasks, completedTasks => completedTasks.Where(w => !w.IsFaulted && !w.IsCanceled), TaskContinuationOptions.None);tfTask.ContinueWith(task=>{var a = list;});});Console.ReadKey();}static void Task_0(){for (var i = 0; i < 1000000; i++){list.Add(i);}}static void Task_1(){for (var i = 0; i < 1000000; i++){list.Add(i);}}static void Task_2(){for (var i = 0; i < 1000000; i++){list.Add(i);}}}

多跑几次这段代码,你几乎可以重现所有可能出现的多线程资源争用异常.

解决方案:给Add方法加锁,代码如下:

    class Program{static object lockObj = new object();static List<long> list = new List<long>();static void Main(string[] args){var t = Task.Run(() =>{var tf = new TaskFactory(TaskCreationOptions.AttachedToParent, TaskContinuationOptions.AttachedToParent);var childTasks = new Task[]{tf.StartNew(()=>Task_0()),tf.StartNew(()=>Task_1()),tf.StartNew(()=>Task_2())};var tfTask=tf.ContinueWhenAll(childTasks, completedTasks => completedTasks.Where(w => !w.IsFaulted && !w.IsCanceled), TaskContinuationOptions.None);tfTask.ContinueWith(task=>{var a = list;});});Console.ReadKey();}static void Task_0(){for (var i = 0; i < 1000000; i++){lock (lockObj){list.Add(i);}}}static void Task_1(){for (var i = 0; i < 1000000; i++){lock (lockObj){list.Add(i);}}}static void Task_2(){for (var i = 0; i < 1000000; i++){lock (lockObj){list.Add(i);}}}}

ok,解决了问题,当然这不是最好的解决方案,你完全可以通过适配器模式,去扩展一个线程安全的List类型,这里我就不写了.

转载于:https://www.cnblogs.com/GreenLeaves/p/10092128.html

C# 多线程之List的线程安全问题相关推荐

  1. java线程之List集合并发安全问题及解决方案

    一.问题代码 任务:执行10轮次,使用多线程,给list集合添加元素,查看每次执行的结果. public static void main(String[] args) throws Interrup ...

  2. linux 线程pthread_detach,linux线程之pthread_join和pthread_detach

    在任何一个时间点上,线程是可结合的(joinable)或者是分离的(detached).一个可结合的线程能够被其他线程收回其资源和杀死.在 被其他线程回收之前,它的存储器资源(例如栈)是不释放的.相反 ...

  3. Android多线程之ArrayBlockingQueue源码解析

    阻塞队列系列 Android多线程之LinkedBlockingQueue源码解析 Android多线程之SynchronousQueue源码解析 Andorid多线程之DelayQueue源码分析 ...

  4. Asp.Net Core 轻松学-多线程之Task快速上手

    Asp.Net Core 轻松学-多线程之Task快速上手 原文:Asp.Net Core 轻松学-多线程之Task快速上手 前言     Task是从 .NET Framework 4 开始引入的一 ...

  5. 多线程别怕,有锁就安全;(解决线程安全问题)

    多线程de小事情 导航不迷路: 程序.进程以及线程的爱恨情仇 最简单实现多线程的方法(Thread) 简单易懂的多线程(通过实现Runnable接口实现多线程) 常用获取线程基本信息的方法(新手专属) ...

  6. JAVA多线程之wait/notify

    本文主要学习JAVA多线程中的 wait()方法 与 notify()/notifyAll()方法的用法. ①wait() 与 notify/notifyAll 方法必须在同步代码块中使用 ②wait ...

  7. 浅析Java各种变量线程安全问题

    静态方法 非静态方法 静态变量 实例变量 局部变量 静态方法(Static Method) 与静态成员变量一样,属于类本身,在类装载的时候被装载到内存(Memory),不自动进行销毁,会一直存在于内存 ...

  8. java线程安全问题之静态变量、实例变量、局部变量

    转载 java多线程编程中,存在很多线程安全问题,至于什么是线程安全呢,给出一个通俗易懂的概念还是蛮难的,如同<java并发编程实践>中所说: 写道 给线程安全下定义比较困难.存在很多种定 ...

  9. Java多线程之Callable、Future和FutureTask

    Java多线程之Callable接口 自己想总结一下的,看到一篇总结的更好的博客,就转载了,突然感觉真轻松,哈哈哈哈 文章转载于:Matrix海子:Java并发编程:Callable.Future和F ...

最新文章

  1. 我把 Spring Boot 的 banner 换成了美女,老板说工作不饱和,建议安排加班
  2. 1562. [NOI2009]变换序列【二分图】
  3. 基于矩阵分解的推荐算法,简单入门
  4. python测试框架untest怎么循环执行_Python自动化测试-Unittest单元测试框架详解
  5. 48. Rotate Image ~
  6. 秒杀场景_多线程异步抢单队列分析与实现_02
  7. windows 7/2008系统字体变成黑体解决
  8. android.os文件,使用android.os.memoryfile的文件IO
  9. 书店计算机管理制度范文,书店管理制度
  10. IPEX: SMA/UFL/IPEX/IPX接头,各代区别
  11. 奔图 Pantum M6550 打印机驱动
  12. 【20保研】厦门大学信息学院2019年全国优秀大学生暑期夏令营招生简章
  13. NVIDIA GPU简史、命名规则及基础知识
  14. 火星南极有水,会有生命吗?
  15. 一名优秀的数据科学家,需要具备哪些基本能力?
  16. 当代年轻人该如何跨越阶层?
  17. ss服务器多端口配置及密码设置^_^
  18. 设计模式学习笔记(二十一:访问者模式)
  19. flex布局(flex容器,flex属性)
  20. python爬虫 多线程 爬取网站排行榜上的所有小说

热门文章

  1. boost::hana::cycle用法的测试程序
  2. boost::leaf::result用法的测试程序
  3. boost::graph模块BC聚类算法程序的实现
  4. GDCM:gdcm::PhotometricInterpretation的测试程序
  5. ITK:将图像粘贴到另一个
  6. DCMTK:查询/检索服务类用户(C-GET操作)
  7. QDoc状态status
  8. C语言实现冒泡排序(bubble排序)算法(附完整源码)
  9. C语言递归遍历一棵二叉树(附完整源码)
  10. C++结构与联合有和区别?