C# List 并发丢数据问题原因及解决方案

项目中出了个 BUG,就在我眼皮子底下,很明显的一个 BUG,愣是看了两天才看出来。

我有多个任务并发,任务执行完成后都有一个返回结果,我用一个 List 将结果收集起来,等所有任务完成后,发送出去。结果一直 丢数据。

我反复检查逻辑都没有问题,最后恍然 List 是非线程安全的。

大家都知道 List 是非线程安全的,但是如果仅有 Add 操作呢?估计有些人就会认为没问题。

下面的代码,期望输出的结果是 1000,然而,注释掉 lock 后,结果就不一样了。

class Program
{
 static List<Person> persons;

 static void Main(string[] args)
 {
  persons = new List<Person>();

  object sync = new object();

  Parallel.For(0, 1000, (i) =>
  {
   Person person = new Person
   {
    ID = i,
    Name = "name" + i
   };
   lock (sync)
    persons.Add(person);
  });

  Console.WriteLine(persons.Count);
  Console.ReadLine();
 }

 class Person
 {
  public int ID { get; set; }
  public string Name { get; set; }
 }
}

利用安全集合ConcurrentBag取代list

测试程序

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyConcurrent
{
  class Program
  {
    /// <summary>
    /// ConcurrentBag并发安全集合
    /// </summary>
    public static void ConcurrentBagWithPallel()
    {
      ConcurrentBag<int> list = new ConcurrentBag<int>();
      Parallel.For(0, 10000, item =>
      {
        list.Add(item);
      });
      Console.WriteLine("ConcurrentBag's count is {0}", list.Count());
      int n = 0;
      foreach (int i in list)
      {
        if (n > 10)
          break;
        n++;
        Console.WriteLine("Item[{0}] = {1}", n, i);
      }
      Console.WriteLine("ConcurrentBag's max item is {0}", list.Max());
    }

    /// <summary>
    /// 函数入口
    /// </summary>
    /// <param name="args"></param>
    static void Main(string[] args)
    {
      Console.WriteLine("ConcurrentBagWithPallel is runing" );
      ConcurrentBagWithPallel();

      Console.Read();
    }

以上就是C# List 并发丢数据问题原因及解决方案的详细内容,更多关于C# List 并发丢数据的资料请关注我们其它相关文章!

(0)

相关推荐

  • c#使用linq把多列的List转化为只有指定列的List

    使用linq把多列的List转化为只有指定列的List 1.方式一 2.方式二 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们.

  • 详解C# List<T>的Contains,Exists,Any,Where性能对比

    测试 新建一个Person类 public class Person { public Person(string name,int id) { Name = name; Id = id; } public string Name { get; set; } public int Id { get; set; } } 初始化List 中有一百万条数据,然后分别通过每种方法判断xiaoming是否在List中,代码如下 static void Main(string[] args) { List<

  • C# 中的List.Sort()--集合排序方法全面解析

    在C#中,List.Sort() 不仅为我们提供了默认的排序方法,还为我们提供了4种自定义排序的方法,通过默认排序方法,我们无需重写任何Sort()方法的实现代码,就能对单参数类型的List数据进行单一规则的排序,如果通过对这些方法进行改进我们可以轻松做到对多参数.多规则的复杂排序. 下面是C#自定义排序的4种方法: List<T>.Sort(); List<T>.Sort(IComparer<T> Comparer); List<T>.Sort(int i

  • C# 多线程处理List数据的示例代码

    代码思路 将要处理的数据放到ConcurrentQueue中,然后开启多个线程去处理数据,处理完成后,再到队列中获取下一个待处理数据. ConcurrentQueue 表示线程安全的先进先出 (FIFO) 集合,属于 System.Collections.Concurrent 命名空间下的一个数据结构 直接上代码 /// <summary> /// 多线程处理数据(无返回值) /// </summary> /// <typeparam name="T"&g

  • 浅谈C#中ListView类的用法

    一.ListView类 1.常用的基本属性: (1)FullRowSelect:设置是否行选择模式.(默认为false) 提示:只有在Details视图该属性才有意义. (2)GridLines:设置行和列之间是否显示网格线.(默认为false)提示:只有在Details视图该属性才有意义. (3)AllowColumnReorder:设置是否可拖动列标头来对改变列的顺序.(默认为false)提示:只有在Details视图该属性才有意义. (4)View:获取或设置项在控件中的显示方式,包括De

  • 一文看懂C#中List的扩容机制

    一:背景 1. 讲故事 在前一篇大内存排查中,我们看到了Dictionary正在做扩容操作,当时这个字典的count=251w,你把字典玩的66飞起,其实都是底层为你负重前行,比如其中的扩容机制,当你遇到几百万甚至千万的大集合这个扩容机制还真的需要挖一下,免的入戏太深,难以自拔. 二:List扩容机制 1. 如何查看 要想看它的扩容机制,可以用ILSpy去看看List的源码即可,非常简单. 从源码的 int num = (_items.Length == 0) ? 4 : (_items.Len

  • C#中List集合使用Max()方法查找到最大值的实例

    在C#的List集合操作中,有时候需要查找到List集合中的最大值,此时可以使用List集合的扩展方法Max方法,Max方法有2种形式,一种是不带任何参数的形式,适用于一些值类型变量的List集合,另一种是带Lambda表达式书写形式的,此方法可适用于获取List集合中某一个属性的最大值. (1)不带任何参数的Max方法形式举例,程序调用形式如下: List list1 = new List() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; var maxValue =

  • C# Winfom 中ListBox的简单用法详解

    1.如何添加listBox的值 this.listBox1.Items.Add("张晓东"); 2.如何判断listBox集合是否添加过 //检查添加值是否添加过 if(this.listBox1.items.Contains("张晓东")){ MessageBox.show("集合成员已添加过!"); } else{ //执行添加集合成员 } 3.如何获取listBox选中的值 //判断所有选中项集合大于0 if(this.listBox1.S

  • C# List集合中获取重复值及集合运算详解

    话不多说,直接上实例: 一.获取集合内重复值 public void GetDuplicateValue() { List<string> lisA = new List<string> { "A", "B", "C", "A" }; //方式一 借助字典 Dictionary<string, int> dic = new Dictionary<string, int>(); l

  • C# List 并发丢数据问题原因及解决方案

    项目中出了个 BUG,就在我眼皮子底下,很明显的一个 BUG,愣是看了两天才看出来. 我有多个任务并发,任务执行完成后都有一个返回结果,我用一个 List 将结果收集起来,等所有任务完成后,发送出去.结果一直 丢数据. 我反复检查逻辑都没有问题,最后恍然 List 是非线程安全的. 大家都知道 List 是非线程安全的,但是如果仅有 Add 操作呢?估计有些人就会认为没问题. 下面的代码,期望输出的结果是 1000,然而,注释掉 lock 后,结果就不一样了. class Program { s

  • 高并发系统数据幂等的解决方案

    前言 在系统开发过程中,经常遇到数据重复插入.重复更新.消息重发发送等等问题,因为应用系统的复杂逻辑以及网络交互存在的不确定性,会导致这一重复现象,但是有些逻辑是需要有幂等特性的,否则造成的后果会比较严重,例如订单重复创建,这时候带来的问题可是非同一般啊. 什么是系统的幂等性 幂等是数据中得一个概念,表示N次变换和1次变换的结果相同. 高并发的系统如何保证幂等性? 1.查询 查询的API,可以说是天然的幂等性,因为你查询一次和查询两次,对于系统来讲,没有任何数据的变更,所以,查询一次和查询多次一

  • MySQL 丢失数据的原因及解决

    前言 最近偶尔会收到用户反馈数据不见了,数据丢失了的问题.从现象上来看,这类问题在数据库层面就是紧急程度最高的那一类了,抛开客观条件来说,针对这一类问题的恢复手段几乎只有备份恢复+回放 Binlog,耗时一般比较久,对业务的影响也会很大. 但是,作为一个以稳定为主的软件,其实丢数据的概率是非常低的,所以这些反馈的问题,是不是真的"丢失数据了"? 问题描述 某日中午接到用户反馈,用业务账号登录数据库以后,业务库不见了. 原因分析 收到这个问题的时候,气氛还是很紧张的,一边联系用户授权登录

  • Java之Rsync并发迁移数据并校验详解

    java调用Rsync并发迁移数据并执行校验 java代码如下 RsyncFile.java import lombok.NoArgsConstructor; import lombok.SneakyThrows; import java.io.*; import java.util.ArrayList; import java.util.Date; import java.util.concurrent.*; /** * @ClassName RsyncFile * @Descriptiom

  • SQLServer中防止并发插入重复数据的方法详解

    SQLServer中防止并发插入重复数据,大致有以下几种方法: 1.使用Primary Key,Unique Key等在数据库层面让重复数据无法插入. 2.插入时使用条件 insert into Table(****) select **** where not exists(select 1 from Table where ****); 3.使用SERIALIZABLE隔离级别,并且使用updlock或者xlock锁提示(等效于在默认隔离级别下使用(updlock,holdlock)或(xl

  • Springboot使用Junit测试没有插入数据的原因

    从写Junit开始笔者就有一个疑问,为什么执行插入测试方法成功了但是数据库里却没有对应数据,那怎么测试的呢?今天查阅了资料找到了原因 1.Junit测试原理 springboot中使用junit编写单元测试默认是事物回滚的,这样测试的脏数据不影响数据库,即实际上是执行了对应的插入操作,但是完成操作后执行了事务回滚操作,从而数据库中没有对应数据. 2.关闭自动事务回滚 在对应的测试方法上添加@Rollback(false)关闭回滚. 补充知识:Spring Boot Junit无法执行问题汇总 S

  • 快速解决mysql导数据时,格式不对、导入慢、丢数据的问题

    如果希望一劳永逸的解决慢的问题,不妨把你的mysql升级到mysql8.0吧,mysql8.0默认的字符集已经从latin1改为utf8mb4,因此现在UTF8的速度要快得多,在特定查询时速度提高了1800%! 但是如果时间等不及,就先用下面的办法快速解决一下. 问题一:格式不对(常出现时间格式不对的情况): 方法1:将excel文件另存为csv,再导入数据库: 方法2:导入的第一步时,默认编码方式是65001(UTF-8),可以尝试选择[10008 (MAC - Simplified Chin

  • java迭代器移除元素出现并发修改异常的原因及解决

    迭代器(Iterator的对象)主要用于遍历集合,体现的就是迭代器模式. Iterator接口定义了以下四种方法. boolean hasNext():如果集合还没遍历完就返回true. Object next():返回集合里的下一个元素. void remove():删除集合里上一次next方法返回的元素. void forEachRemaining(Consumer action):这是java8新增的默认方法,可用Lambda表达式遍历数组. 使用迭代器遍历元素时不能不能通过Collect

  • Kotlin遍历集合导致并发修改异常的原因和解决方法

    各位android 老司机们,对于android 遍历结合的时候,发生并发修改异常一定毫不陌生: 之前看到过一篇文章, 在阿里巴巴Java开发手册中,有这样一条规定: 其实,增强for循环也是Java给我们提供的一个语法糖,如果将以上代码编译后的class文件进行反编译(使用jad工具)的话,可以得到以下代码: 1.原因:(其实我都不想在各位老司机面前再赘述这个了.-_-||) 这个异常产生的原因是,迭代器依赖于集合而存在,在判断成功后,集合中添加了新的元素,而迭代器并不知道,所有就报错了.其实

  • Mybatis-plus自动填充不生效或自动填充数据为null原因及解决方案

    目录 问题一:自动填充的数据为null 问题二:使用mybatis-plus的乐观锁后发现自动填充的updateTime字段不自动填充了 小结 昨天使用mybatis-plus.使用自动填充后发现了两个问题. 一个是填充数据为null, 一个是当使用了mybatis-plus的乐观锁,自动填充就失效了 开始在网上看,有人说是mybatis的bug,我想不会我这么快就遇到了bug.后面我通过idea的(ctrl+B)看他的源码.发现这不是bug,而是一个非常巧妙的设计,当然也可能是之前有bug,我

随机推荐