zoukankan      html  css  js  c++  java
  • .Net 线程安全集合

    .Net 提供了基于生产-消费模式的集合类,这些集合对多线程访问安全,定义在System.Collections.Concurrent名称空间中。这个名称空间中包括基础接口IProduceConsumerCollection,这个接口定义了线程安全集合的基本操作。这个名称空间中还包括常用的集合:

    • BlockingCollection
    • ConcurrentBag
    • ConcurentDictionary<TKey,TValue>
    • ConcurrentQueue
    • ConcurentStack

    在使用生产-消费模式时,我们经常使用两个线程,在一个线程向集合添加数据,在另一个线程从集合中提取数据进行处理。我们可以使用实现IProduceConsumerCollection接口的集合,比如ConcurrentQueue等等。通常将从集合取数据的代码放在一个无尽循环中,如果集合中没有数据就继续循环。很多情况下,我们希望如果集合中没有数据,这个线程阻塞等待,直到有数据时再继续。这时我们可以使用BlockingCollection,这个集合提供了Add(添加数据)和Take(阻塞获取数据)方法。

    下面是BlockingCollection的示例。这个集合类的Take方法可以从集合中获取并去掉一个对象,当集合为空时,可以使线程处于阻塞状态。

    Console.WriteLine("--------------------------------");
    Console.WriteLine("测试一个线程向集合添加数据,另一个线程读取数据,请输入人名,输入exit退出");
    BlockingCollection<string> names=new BlockingCollection<string>();
    
    Task.Run(() =>
    {
        while (true)
        {
            var name = names.Take();
            Console.WriteLine("你好,"+name);
        }
    
    });
    
    var name = Console.ReadLine();
    while (name!="exit")
    {
        if(!string.IsNullOrEmpty(name))   names.Add(name);
        name = Console.ReadLine();
    }
    

    BlockingCollection的另一个功能是可以封装其它的IProduceConsumerCollection集合,实现不同的添加和获取顺序,比如,如果在构造函数中传入ConcurrentQueue,添加和获取就与队列相同——“先进先出”,如果传入ConcurrentStack,顺序就与堆栈相同——“先进后出”,下面是示例代码:

    using System.Collections.Concurrent;
    
    Console.WriteLine("--------------------------------");
    Console.WriteLine("测试BlockingCollection 和 ConcurrentQueue");
    
    var queue = new ConcurrentQueue<string>();
    var blockqueue= new BlockingCollection<string>(queue, 100);
    
    Console.WriteLine("加入name1");
    blockqueue.Add("name1");
    Console.WriteLine("加入name2");
    blockqueue.Add("name2");
    Console.WriteLine("加入name3");
    blockqueue.Add("name3");
    
    Console.WriteLine(blockqueue.Take());
    Console.WriteLine(blockqueue.Take());
    Console.WriteLine(blockqueue.Take());
    
    Console.WriteLine("--------------------------------");
    Console.WriteLine("测试BlockingCollection 和 ConcurrentStack");
    
    var cq = new ConcurrentStack<string>();
    var bc = new BlockingCollection<string>(cq, 100);
    
    Console.WriteLine("加入name1");
    bc.Add("name1");
    Console.WriteLine("加入name2");
    bc.Add("name2");
    Console.WriteLine("加入name3");
    bc.Add("name3");
    
    Console.WriteLine(bc.Take());
    Console.WriteLine(bc.Take());
    Console.WriteLine(bc.Take());
    

    ConcurrentBag需要特别说明一下,在“纯生产-消费”场景中(一个线程要么向集合添加项目,要么从集合中获取项目,但不能即添加又获取),ConcurrentBag性能要比其他类型的集合慢,但在“混合生产-消费”场景中(一个线程即可以向集合添加项目,也可以获取项目),ConcurrentBag的性能要比其它类型的集合快。

    本文来自博客园,作者:寻找无名的特质,转载请注明原文链接:https://www.cnblogs.com/zhenl/p/15768806.html

  • 相关阅读:
    Java LinkedList 源码剖析
    Java并发编程:线程池的使用
    Java 线程池的原理与实现
    多线程JAVA篇(一)
    软件开发中会用到的图
    linux文件名匹配——通配符使用
    XModem协议
    dmesg 命令七种用法
    定位精度单位CEP、RMS、2DRMS常识
    5G NR 技术简介
  • 原文地址:https://www.cnblogs.com/zhenl/p/15768806.html
Copyright © 2011-2022 走看看