简单画了一张图 (灵魂画手 →_→)

如图 ConcurrentDictionary 其中有个tables 对象主要存储,而这个 tables 是一个 很多区块的 数组 ,每个区块 又是一个node的链表 (ps: 一个node 就是一个key value 对)

具体实现如下(ps 代码摘自 net4.5):

   private volatile ConcurrentDictionary<TKey, TValue>.Tables m_tables;

 private class Tables
{
internal readonly ConcurrentDictionary<TKey, TValue>.Node[] m_buckets;
internal readonly object[] m_locks;
internal volatile int[] m_countPerLock;
internal readonly IEqualityComparer<TKey> m_comparer; internal Tables(ConcurrentDictionary<TKey, TValue>.Node[] buckets, object[] locks, int[] countPerLock, IEqualityComparer<TKey> comparer)
{
this.m_buckets = buckets;
this.m_locks = locks;
this.m_countPerLock = countPerLock;
this.m_comparer = comparer;
}
} private class Node
{
internal TKey m_key;
internal TValue m_value;
internal volatile ConcurrentDictionary<TKey, TValue>.Node m_next;
internal int m_hashcode; internal Node(TKey key, TValue value, int hashcode, ConcurrentDictionary<TKey, TValue>.Node next)
{
this.m_key = key;
this.m_value = value;
this.m_next = next;
this.m_hashcode = hashcode;
}
}

看 这个Node类是一个带next 指针的结构 ,一个node就是链表  ,而Tables类中 m_buckets 变量便是一个 存储了n个链表的列表结构

其中Tables类中有个变量名为 countPerLock 类型为 int[] 便是图中最下面那个框 这个,这个变量 主要是用来 统计字典中数据的个数 ,这个 countPerLock 与m_buckets 数量 一一对应,一个node对应countPerLock 中的一个元素。Count()这个方法便是主要使用这个元素经行统计。这样的好处是不用遍历node链表。

最重要的是Tables 中m_locks的实现。 这是一个锁的列表 其中用来控制 多线程读取修改时 控制的区块 。

当字典初始化的时候 m_locks 的数量为 cpu内核数*4(ps:例如i7 就是8*4=32) 而  m_buckets 数量初始化是31(有个小条件是m_locks>=m_buckets 时 m_locks=m_buckets) 所以i7 下 m_buckets 和 m_locks 都是32个 ,理论上再,不添加新节点的时候 一个区块对应 一个锁。

m_locks 初始化时是默认值是 cpu内核数*4  最大值是 1024个

m_buckets初始化默认值 31  最大值是2146435071

也就是说 如果字典中数据量大的时候 是一个锁对象 对应n个Node链表。

关于ConcurrentDictionary中所有读取操作

例如Keys Values Count 这类的属性 会对锁定 m_locks 中所有的锁对象 所以需要谨慎使用。

而常用的索引器[]和 TryGetValue 等方法 未锁定任何锁对象,并通过 Volatile.Read 原子性读取 对应的Node链表 遍历中所有元素 直到找到 对应的key 为止。

关于ConcurrentDictionary中所有写操作

当添加一个新数据时 方法会计算key的hashcode  是放到哪个node里表中 然后锁定对应的锁对象,自后 通过 Volatile.Write 方法 替换新的Node的指向 , 这时node为新的值 它的next 指向原先的Node值。

 private void GetBucketAndLockNo(int hashcode, out int bucketNo, out int lockNo, int bucketCount, int lockCount)
{
bucketNo = (hashcode & int.MaxValue) % bucketCount; //Node的位置
lockNo = bucketNo % lockCount; // 锁位置
} Volatile.Write<ConcurrentDictionary<TKey, TValue>.Node>(ref tables.m_buckets[bucketNo], new ConcurrentDictionary<TKey, TValue>.Node(key, value, hashCode, tables.m_buckets[bucketNo]));

为什么这么设计?

对于多线程 这种多个链表 多个锁对象 可以提升 多个线程同时操作的可能性 ,因为很大的程度上写操作的数据  并不是一个锁对象负责的。

同时链式的存储 对于添加对象而言 内存的操作更方便

浅析C#中 ConcurrentDictionary的实现的更多相关文章

  1. 浅析Java中的final关键字

    浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...

  2. 浅析mongodb中group分组

    这篇文章主要介绍了浅析mongodb中group分组的实现方法及示例,非常的简单实用,有需要的小伙伴可以参考下. group做的聚合有些复杂.先选定分组所依据的键,此后MongoDB就会将集合依据选定 ...

  3. 浅析py-faster-rcnn中不同版本caffe的安装及其对应不同版本cudnn的解决方案

    浅析py-faster-rcnn中不同版本caffe的安装及其对应不同版本cudnn的解决方案 本文是截止目前为止最强攻略,按照本文方法基本可以无压力应对caffe和Ross B. Girshick的 ...

  4. 浅析JS中的模块规范(CommonJS,AMD,CMD)////////////////////////zzzzzz

    浅析JS中的模块规范(CommonJS,AMD,CMD)   如果你听过js模块化这个东西,那么你就应该听过或CommonJS或AMD甚至是CMD这些规范咯,我也听过,但之前也真的是听听而已.     ...

  5. 浅析Java中的访问权限控制

    浅析Java中的访问权限控制 今天我们来一起了解一下Java语言中的访问权限控制.在讨论访问权限控制之前,先来讨论一下为何需要访问权限控制.考虑两个场景: 场景1:工程师A编写了一个类ClassA,但 ...

  6. [转载]浅析Java中的final关键字

    浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...

  7. 浅析 JavaScript 中的 函数 currying 柯里化

    原文:浅析 JavaScript 中的 函数 currying 柯里化 何为Curry化/柯里化? curry化来源与数学家 Haskell Curry的名字 (编程语言 Haskell也是以他的名字 ...

  8. 浅析 JavaScript 中的 函数 uncurrying 反柯里化

    柯里化 柯里化又称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果. 因此柯里化的过程是 ...

  9. 【转】浅析Java中的final关键字

    谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法. ...

随机推荐

  1. 20162303实验四 Android程序设计

    北京电子科技学院(BESTI) 实 验 报 告 课程:程序设计与数据结构 班级: 1623 姓名: 石亚鑫 学号:20162303 成绩: 2分 指导教师:娄嘉鹏 王志强 实验日期:5月26日 实验密 ...

  2. 20162303实验三 敏捷开发与XP实践-1

    北京电子科技学院(BESTI) 实 验 报 告 课程:程序设计与数据结构 班级: 1623 姓名: 石亚鑫 学号:20162303 成绩: 2分 指导教师:娄嘉鹏 王志强 实验日期:5月12日 实验密 ...

  3. iOS 自定义对象及子类及模型套模型的拷贝、归档存储的通用代码

    一.runtime实现通用copy 如果自定义类的子类,模型套模型你真的会copy吗,小心有坑. copy需要自定义类继承NSCopying协议 #import <objc/runtime.h& ...

  4. Web安全测试指南--认证

    认证: 5.1.1.敏感数据传输: 编号 Web_Authen_01_01 用例名称 敏感数据传输保密性测试 用例描述 测试敏感数据是否通过加密通道进行传输以防止信息泄漏. 严重级别 高 前置条件 1 ...

  5. ArcGIS10.1发布WFS-T服务

    官方帮助文档:http://resources.arcgis.com/zh-cn/help/main/10.1/index.html#/na/0154000003m3000000/ 本文介绍了如何使用 ...

  6. matlab的输出流控制

    Matlab之print,fprint,fscanf,disp函数 print: print函数可以把函数图形保存成图片: minbnd = -4*pi; maxbnd = 4*pi; t = min ...

  7. JS的join方法

    join() 方法用于把数组中的所有元素放入一个字符串. 元素是通过指定的分隔符进行分隔的. 例子 1 在本例中,我们将创建一个数组,然后把它的所有元素放入一个字符串: <script type ...

  8. JAVA HDFS API Client 连接HA

    如果Hadoop开启HA,那么用Java Client连接Hive的时候,需要指定一些额外的参数 package cn.itacst.hadoop.hdfs; import java.io.FileI ...

  9. iOS:创建单例对象的两种方式

    单例模式:创建单例对象的两种方式 方式一:iOS4版本之前      static SingleClassManager *singleManager = nil;      +(SingleClas ...

  10. ZOJ3622 Magic Number(水题)

    分析: 举个样例xxx(三位数)为魔力数,则xxx|(xxx+1000*y),那么xxx|1000,这个就是结论 同理:四位数xxxx|10000,五位数xxxxx|100000 代码: #inclu ...