ConcurrentDictionary 与 Dictionary

ASP.NET中ConcurrentDictionary是.Net4 增加的,与 Dictionary 最主要区别是, 前者是线程安全的集合,可以由多个线程同时并发读写Key-value。

那么 什么是线程安全?线程安全和非线程安全有什么区别?分别在什么情况下使用?

什么是线程安全 ? 

  线程安全就是指多线程反问时候,采用了加锁机制。

  当线程A访问某个对象时候,采用了保护机制,这时候另一个线程B访问该对象不产生异常。

线程安全和非线程安全有什么区别?

  

  非线程安全是指多线程操作同一个对象可能会出现问题。

  而线程安全则是多线程操作同一个对象不会有问题。 

分别在什么情况下使用?

  当多线程情况下,对 全局变量、静态变量 进行访问或者操作数据的时候, 建议使用线程安全, 非线程安全有几率出现异常。

接下来放一个实例:

  分别使用 ConcurrentDictionary  与 Dictionary  根据key读取value, 当key不存在的时候进行写入并读取,key存在的时候直接读取对应的value。

  

  

1.定一个接口:

  

public interface IGetLogger
    {
        string GetLogger(string cmdId);
    }

2. Dictionary 实现:

   public class DictionaryLogger : IGetLogger
    {
        static Dictionary<string, string>  loggreDic = new Dictionary<string, string>();
        public string GetLogger(string cmdId)
        {
            if (!loggreDic.ContainsKey(cmdId))
            {
                loggreDic.Add(cmdId, $"AAA.{cmdId}");
            }
            return loggreDic[cmdId];
        }
    }

3. ConcurrentDictionary   实现:

  public class ConcurrentDictionaryLogger : IGetLogger
    {
        static ConcurrentDictionary<string, string> loggreDic = new ConcurrentDictionary<string, string>();

        public string GetLogger(string cmdId)
        {
            if (!loggreDic.ContainsKey(cmdId))
            {
                loggreDic.TryAdd(cmdId, $"ConcurrentDictionary.{cmdId}");
            }
            return loggreDic[cmdId];
        }
    }
public partial class ConcurrentDictionaryForm : Form
    {
        public ConcurrentDictionaryForm()
        {
            Console.WriteLine("欢迎来到ConcurrentDictionary线程安全");
            InitializeComponent();
        }

        /// <summary>
        /// 非线程安全
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Dictionary_Click(object sender, EventArgs e)
        {
            int threadCount = 5000;
            CountDownLatch latch = new CountDownLatch(threadCount);
            object state = new object();
            for (int i = 0; i < threadCount; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(new WasteTimeDic(latch).DoSth), i);
            }
            latch.Await();
        }

        /// <summary>
        /// 线程安全
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ConcurrentDictionary_Click(object sender, EventArgs e)
        {

            int threadCount = 5000;

            CountDownLatch latch = new CountDownLatch(threadCount);
            object state = new object();
            for (int i = 0; i < threadCount; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(new WasteTime(latch).DoSth), i);
            }
            latch.Await();

        }

    }
CountDownLatch 是一个自定义个的并发检测类:
    public class CountDownLatch
    {
        private object lockObj = new Object();
        private int counter;

        public CountDownLatch(int counter)
        {
            this.counter = counter;
        }

        public void Await()
        {
            lock (lockObj)
            {
                while (counter > 0)
                {
                    Monitor.Wait(lockObj);
                }
            }
        }

        public void CountDown()
        {
            lock (lockObj)
            {
                counter--;
                Monitor.PulseAll(lockObj);
            }
        }
    }

  public class WasteTime
    {
        private CountDownLatch latch; 

        public WasteTime(CountDownLatch latch)
        {
            this.latch = latch;
        }

        public void DoSth(object state)
        {
            //模拟耗时操作
            //System.Threading.Thread.Sleep(new Random().Next(5) * 1000);
            //Console.WriteLine("state:"+ Convert.ToInt32(state));

            IGetLogger conLogger = new ConcurrentDictionaryLogger();
            try
            {
                Console.WriteLine($"{state}GetLogger:{conLogger.GetLogger("BBB")}");
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("第{0}个线程出现问题", state));
            }
            //执行完成注意调用CountDown()方法
            this.latch.CountDown();
        }

    }

    public class WasteTimeDic
    {
        private CountDownLatch latch;

        public WasteTimeDic(CountDownLatch latch)
        {
            this.latch = latch;
        }

        public void DoSth(object state)
        {
            //模拟耗时操作
            //System.Threading.Thread.Sleep(new Random().Next(5) * 1000);
            //Console.WriteLine("state:"+ Convert.ToInt32(state));
            IGetLogger conLogger = new DictionaryLogger();
            try
            {
                Console.WriteLine($"{state}GetLoggerDic:{conLogger.GetLogger("AAA")}");
            }
            catch (Exception ex)
            {
                Console.WriteLine(string.Format("第{0}个线程出现问题", state));
            }
            //执行完成注意调用CountDown()方法
            this.latch.CountDown();
        }

    }
会有一定几率出现异常情况:

原文地址:https://www.cnblogs.com/dragon-L/p/8442655.html

时间: 2024-10-17 03:22:14

ConcurrentDictionary 与 Dictionary的相关文章

ConcurrentDictionary与Dictionary

一.Dictionary<TKey, TValue> 1.泛型类提供了从一组键到一组值的映射.通过键来检索值的速度是非常快的,这是因为 Dictionary<TKey,TValue> 类是作为一个哈希表来实现的.检索速度取决于为 TKey 指定的类型的哈希算法的质量. 2.TValue可以是值类型,数组,类或其他. 3.一个类的实例里,有个属性是个字典,我们不加考虑的会用Dictionary,而当这个属性被提升为static静态的(类级别的)时候,我们就要考虑它的线程安全性了,因为

OSS.Common获取枚举字典列表标准库支持

介绍了OSS.Common的标准库支持扩展,也列举了可能遇到问题的解决方案.由于时间有限,同时.net standard暂时还没有提供对DescriptionAttribute的支持,所以其中的转化枚举到字典列表的扩展当时按照第一种处理方式先行屏蔽,这次按照第三种方式完善一下. 既然.net standard 下没有提供对DescriptAttribute的支持,首先我先自定义一个Attribute来补充: [AttributeUsage(AttributeTargets.All, AllowM

ASP.NET Core 依赖注入最佳实践——提示与技巧

在这篇文章,我将分享一些在ASP.NET Core程序中使用依赖注入的个人经验和建议.这些原则背后的动机如下: 高效地设计服务和它们的依赖. 预防多线程问题. 预防内存泄漏. 预防潜在的BUG. 这篇文章假设你已经基本熟悉依赖注入和ASP.NET Core.如果不是,则先阅读文章: 在ASP.NET Core中使用依赖注入 基础 构造函数注入 构造函数注入常用于在服务构建上定义和获取服务依赖.例如: 1 public class ProductService 2 { 3 private read

ConsurrentDictionary并发字典知多少?

背景 在上一篇文章你真的了解字典吗?一文中我介绍了Hash Function和字典的工作的基本原理. 有网友在文章底部评论,说我的Remove和Add方法没有考虑线程安全问题. https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?redirectedfrom=MSDN&view=netframework-4.7.2 查阅相关资料后,发现字典.net中Dictionary本身时不支持

hashset hastable dictionary concurrentdictionary区别

1.HashTable 哈希表(HashTable)表示键/值对的集合.在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似key-value的键值对,其中key通常可用来快速查找,同时key是区分大小写:value用于存储对应于key的值.Hashtable中key-value键值对均为object类型,所以Hashtable可以支持任何类型的keyvalue键值对,任何非 null 对象都可以用作键或值. 在哈希

C#中字典集合HashTable、Dictionary、ConcurrentDictionary三者区别

学习参考博客:http://www.cnblogs.com/yinrq/p/5584885.html 使用Stopwatch类测试耗时代码: using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; namespace WebApp { class Program { static

【数据类型】Dictionary 与 ConcurrentDictionary 待续

Dictionary<TKey, TValue> 泛型类提供了从一组键到一组值的映射.通过键来检索值的速度是非常快的,接近于 O(1),这是因为 Dictionary<TKey, TValue> 类是作为一个哈希表来实现的.检索速度取决于为 TKey 指定的类型的哈希算法的质量.TValue可以是值类型,数组,类或其他. 线程安全:CSDN上说法: 只要不修改该集合,Dictionary<TKey, TValue> 就可以同时支持多个阅读器.即便如此,从头到尾对一个集合

c# 扩展方法奇思妙用基础篇五:Dictionary&lt;TKey, TValue&gt; 扩展

Dictionary<TKey, TValue>类是常用的一个基础类,但用起来有时确不是很方便.本文逐一讨论,并使用扩展方法解决. 向字典中添加键和值 添加键和值使用 Add 方法,但很多时候,我们是不敢轻易添加的,因为 Dictionary<TKey, TValue>不允许重复,尝试添加重复的键时 Add 方法引发 ArgumentException. 大多时候,我们都会写成以下的样子: var dict = new Dictionary<int, string>()

Hastable和Dictionary的区别

1:单线程程序中推荐使用 Dictionary, 有泛型优势, 且读取速度较快, 容量利用更充分. 2:多线程程序中推荐使用 Hashtable, 默认的 Hashtable 允许单线程写入, 多线程读取, 对 Hashtable 进一步调用 Synchronized() 方法可以获得完全线程安全的类型. 而 Dictionary 非线程安全, 必须人为使用 lock 语句进行保护, 效率大减. 3:Dictionary 有按插入顺序排列数据的特性 (注: 但当调用 Remove() 删除过节点