都说ConcurrentDictionary<TKey, TValue>有陷阱
看这么几句解释(英文原帖):
private static void ConcurrentDictionary()
{
var dict = new ConcurrentDictionary<int, string>();
ThreadPool.QueueUserWorkItem(LongGetOrAdd(dict, ));
ThreadPool.QueueUserWorkItem(LongGetOrAdd(dict, ));
} private static WaitCallback LongGetOrAdd(ConcurrentDictionary<int, string> dict, int index)
{
return o => dict.GetOrAdd(index,i =>
{
Console.WriteLine("Adding!");
Thread.SpinWait(); return i.ToString();
}
);
}
1) threadA calls GetOrAdd, finds no item and creates a new item to Add by invoking the valueFactory delegate.
线程A调用GetOrAdd,发现数据不存在并创建了一条新数据,准备调用委托方法添加数据
2) threadB calls GetOrAdd concurrently, its valueFactory delegate is invoked and it arrives at the internal lock before threadA, and so its new key-value pair is added to the dictionary.
线程B现在也在调用GetOrAdd方法,它的委托被调用了,比线程A先进入GetOrAdd内部的锁,因此它创建的键值对被添加到dict中了
3) threadA’s user delegate completes, and the thread arrives at the lock, but now sees that the item exists already
线A的委托执行完成了,并且也获得了GetOrAdd的锁,但是现在发现相关数据已经存在了
4) threadA performs a "Get", and returns the data th at was previously added by threadB.
线程A执行“Get”,返回之前被线程B添加的数据
不止这个英文原帖,好多国内的帖子都在说这个问题。
然而我觉得这并不是个问题,这最多是一个编程时需要注意的事项,微软的这个设计是合理的:ConcurrentDictionary没有理由也没有职责去把外部代码加锁,外部代码的同步应该由
外部控制。回头看看上面的解释,我们发现只不过是传递给ConcurrentDictionary的委托被执行了不止一次,但数据仍然只添加了一次,ConcurrentDictionary已经完全履行了自己的职责,而且MSDN也作了相关的说明(事实上,上面的四句英文也来自MSDN):
The user delegate that is passed to these methods is invoked outside of the dictionary's internal lock. (This is done to prevent unknown code from blocking all threads.)
传递进来的用户委托在字典内部锁的外面调用,这么做是为了防止阻塞所有相关线程,具体参考MSDN。
都说ConcurrentDictionary<TKey, TValue>有陷阱的更多相关文章
- 线程安全集合 ConcurrentDictionary<TKey, TValue> 类
ConcurrentDictionary<TKey, TValue> 类 [表示可由多个线程同时访问的键/值对的线程安全集合.] 支持 .NET Framework 4.0 及以上. 示例 ...
- C#字典 Dictionary<Tkey,Tvalue> 之线程安全问题 ConcurrentDictionary<Tkey,Tvalue> 多线程字典
ConcurrentDictionary<Tkey,Tvalue> Model #region 程序集 mscorlib, Version=4.0.0.0, Culture=neutra ...
- .net源码分析 - ConcurrentDictionary<TKey, TValue>
List源码分析 Dictionary源码分析 ConcurrentDictionary源码分析 继上篇Dictionary源码分析,上篇讲过的在这里不会再重复 ConcurrentDictionar ...
- ConcurrentDictionary<TKey, TValue>的AddOrUpdate方法
https://msdn.microsoft.com/zh-cn/library/ee378665(v=vs.110).aspx 此方法有一共有2个,现在只讨论其中一个 public TValue A ...
- c# 扩展方法奇思妙用基础篇五:Dictionary<TKey, TValue> 扩展
Dictionary<TKey, TValue>类是常用的一个基础类,但用起来有时确不是很方便.本文逐一讨论,并使用扩展方法解决. 向字典中添加键和值 添加键和值使用 Add 方法,但很多 ...
- “线程安全的” Dictionary(TKey,TValue)
这是一篇翻译,专门介绍Dictionary线程安全问题,原文网址如下 http://www.grumpydev.com/2010/02/25/thread-safe-dictionarytkeytva ...
- .net源码分析 – Dictionary<TKey, TValue>
接上篇:.net源码分析 – List<T> Dictionary<TKey, TValue>源码地址:https://github.com/dotnet/corefx/blo ...
- .NET中Dictionary<TKey, TValue>浅析
.NET中Dictionary<TKey, Tvalue>是非常常用的key-value的数据结构,也就是其实就是传说中的哈希表..NET中还有一个叫做Hashtable的类型,两个类型都 ...
- .net学习笔记----有序集合SortedList、SortedList<TKey,TValue>、SortedDictionary<TKey,TValue>
无论是常用的List<T>.Hashtable还是ListDictionary<TKey,TValue>,在保存值的时候都是无序的,而今天要介绍的集合类SortedList和S ...
随机推荐
- python正则实例
# -*- coding: cp936 -*-import reidcardregex=r"^[1-9]\d{14}(\d{2}[0-9x])?$"print re.search( ...
- 同样的一句SQL语句在pl/sql 代码块中count 没有数据,但是直接用SQl 执行却可以count 得到结果
pl/sql 代码块: SELECT count(distinct t2.so_nbr) INTO v_count2 FROM KFGL_YW_STEP_qd t2 WHERE t2.partitio ...
- Unity3d Shader开发(四)UsePass ,GrabPass ,SubShader Tags
(一)UsePass 命令 使用 来自另一个着色器的命名通道. Syntax 语法 UsePass "Shader/Name" 插入所有来自给定着色器中的给定名字的通道.Shade ...
- 重置mysql密码
如何修改mysql root密码 忘记MySQL ROOT密码是在MySQ使用中很常见的问题,可是有很多朋友并不会重置ROOT密码,那叫苦啊,特写此文章与大家交流: 1.编辑MySQL的配置文件:my ...
- css清除浮动的几种方法整理
四种清除浮动方法如下: 1.使用空标签清除浮动.空标签可以是div标签,也可以是P 标签.这种方式是在需要清除浮动的父级元素内部的所有浮动元素后添加这样一个标签 清除浮动,并为其定义CSS代码:cle ...
- [XJOI NOI02015训练题7] B 线线线 【二分】
题目链接:XJOI - NOI2015-07 - B 题目分析 题意:过一个点 P 的所有直线,与点集 Q 的最小距离是多少?一条直线与点集的距离定义为点集中每个点与直线距离的最大值. 题解:二分答案 ...
- csdn搜索技巧
由于CSDN下载资源高级搜索,只能显示10页分页,所以我们换种方法去搜索csdn的资源. 第10页以后没了. 在百度框里面输入如下: jquery site:download.csdn.net 图:
- jquery dom ready, jqery2.1.1实现-源码分析
本文链接http://www.cnblogs.com/Bond/p/4178311.html jquery document ready的实现其很很简,虽说简单,其很很多人还是没去关注过它的实现.我 ...
- nginx 配置的server_name参数(转)
转自:http://www.sklinux.com/373 nginx中的server_name指令主要用于配置基于名称虚拟主机. 一 匹配顺序,server_name指令在接到请求后的匹配顺序如下: ...
- asp.net将数据库中的数据赋给DropDownList
当你选定一项进行其他操作时会重新绑定dropdownlist,这样会重新回到第一项,在page_load里加上判断if(!IsPostBack){'这里是你需要绑定dropdownlist的代码'}. ...