zoukankan      html  css  js  c++  java
  • C# 使用ConcurrentBag类处理集合线程安全问题

    在日常的开发中,经常会遇到多个线程对同一个集合进行读写操作,就难免会出现线程安全问题。

    以下代码,如果使用List<T>就会遇到问题:System.InvalidOperationException:“集合已修改;可能无法执行枚举操作。”。原因是timer2在遍历list的过程当中,timer1修改了list,使其大小发生了变化。所以我们应该使用线程安全的集合来处理。不管是读还是写,同一时刻只能做一件事情,要么读,要么写。

        class Program
        {
            private static List<string> list = new List<string>();
    
            static void Main(string[] args)
            {
                var count = 0;
    
                //任务一
                Timer timer1 = new Timer((obj) =>
                {
                    var str = "a" + ++count;
                    list.Add(str);
                    Console.WriteLine("添加了:" +str);
                }, null, 0, 1000);
    
                //任务二
                Timer timer2 = new Timer((obj) =>
                {
                    foreach (var item in list)
                    {
                        Console.WriteLine("显示:" + item);
                    }
                }, null, 0, 1000);
    
                Console.ReadLine();
            }
        }

    改成:ConcurrentBag<T>就不会了,因为ConcurrentBag<T>是线程安全的。

       class Program
        {
            private static ConcurrentBag<string> list = new ConcurrentBag<string>();
    
            static void Main(string[] args)
            {
                var count = 0;
    
                //任务一
                Timer timer1 = new Timer((obj) =>
                {
                    var str = "a" + ++count;
                    list.Add(str);
                    Console.WriteLine("添加了:" +str);
                }, null, 0, 1000);
    
                //任务二
                Timer timer2 = new Timer((obj) =>
                {
                    foreach (var item in list)
                    {
                        Console.WriteLine("显示:" + item);
                    }
                }, null, 0, 1000);
    
                //任务三
                Timer timer3 = new Timer((obj) =>
                {
                    foreach (var item in list)
                    {
                        Console.WriteLine("删除了:" +item);
                        list.TryTake(out string result);
                    }
                }, null, 0, 3000);
    
                Console.ReadLine();
            }
        }

    参考网址:https://blog.csdn.net/boonya/article/details/80541460

    另外:

    如果想在删除时也是线程安全的,也可使用BlockingCollection<T>类。

    先把需要删除的找出来,然后再遍历删除

                    foreach (var id in ids)
                    {
                        var hub = _hubs.FirstOrDefault(m => m.Id == id);
                        if (hub != null)
                        {
                            _hubs.TryTake(out hub);
                        }
                    }
    private BlockingCollection<HubModel> _hubs;
  • 相关阅读:
    出现System.web.mvc冲突的原因及解决方法CS0433
    看完此文还不懂NB-IoT,你就过来掐死我吧...
    html5调用手机陀螺仪实现方向辨识
    黑盒测试和白盒测试的区别
    CentOS7 下 keepalived 的安装和配置
    centos 下 mysql+keepalived实现双主自由切换
    MySQL 高可用性—keepalived+mysql双主(有详细步骤和全部配置项解释)
    备份VMware虚拟磁盘文件 移植到其他虚拟机
    Centos7 Mysql 双机热备实现数据库高可用
    CentOS7配置Mysql热备份
  • 原文地址:https://www.cnblogs.com/subendong/p/11841906.html
Copyright © 2011-2022 走看看