问题:

代码是在多线程环境下,做了简单的Key是否存的判断, 测试代码如下:

public class Program
{
static Dictionary<string, Logger> loggreDic;
static object loggerDicLocker = new object();
public static void Main()
{
loggreDic = new Dictionary<string, Logger>();
for (int i = 0; i < 100; i++)
{
ThreadPool.QueueUserWorkItem(o =>
{
try
{
var logger = GetLogger("AAA");
}
catch (Exception)
{
Console.WriteLine(string.Format("弟{0}个线程出现问题", o));
} }, i);
}
Console.ReadKey();
} static Logger GetLogger(string cmdId)
{
if (!loggreDic.ContainsKey(cmdId))
{
loggreDic.Add(cmdId, LogManager.GetLogger(string.Format("ChinaPnrApi.{0}", cmdId)));
}
return loggreDic[cmdId];
}
}

可以看到在GetLogger的地方做了判断的处理,但是在多线程的时候还是会出现在取的时候取不到的问题。可以参考下面截图 :

从错误异常很容易判断,是在Dictionary中加了重复的Key造成的.

所以总体上来看这段代码所犯的问题是不是线程安全的代码.

 

解决方案 :

1. 使用Locker解决

2. 使用线程安全的

下面对两种方式都做了实现:

public interface IGetLogger
{
Logger GetLogger(string cmdId);
} public class ConcurrentDictionaryLogger : IGetLogger
{
ConcurrentDictionary<string, Logger> loggreDic = new ConcurrentDictionary<string, Logger>();
public Logger GetLogger(string cmdId)
{
if (!loggreDic.ContainsKey(cmdId))
{
loggreDic.TryAdd(cmdId, LogManager.GetLogger(string.Format("ChinaPnrApi.{0}", cmdId)));
}
return loggreDic[cmdId];
}
} public class LockerDictionaryLogger : IGetLogger
{
Dictionary<string, Logger> loggreDic = new Dictionary<string, Logger>();
object locker = new object();
public Logger GetLogger(string cmdId)
{
if (!loggreDic.ContainsKey(cmdId))
{
lock (locker)
{
if (!loggreDic.ContainsKey(cmdId))
{
loggreDic.Add(cmdId, LogManager.GetLogger(string.Format("ChinaPnrApi.{0}", cmdId)));
}
}
}
return loggreDic[cmdId];
}
}

测试代码如下:

public static void Main()
{
IGetLogger conLogger = new ConcurrentDictionaryLogger(); IGetLogger lockerLogger = new LockerDictionaryLogger(); CodeTimer.Time("使用ConcurrentDictionary", 1000000, () =>
{
ThreadPool.QueueUserWorkItem(o =>
{
try
{
var logger = conLogger.GetLogger("AAA");
if (logger == null)
{
Console.WriteLine(string.Format("弟{0}个线程获取到的值是 NULL", o));
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("弟{0}个线程出现问题, {1}", o, ex.Message));
}
});
}); CodeTimer.Time("使用LockDictionary", 1000000, () =>
{
ThreadPool.QueueUserWorkItem(o =>
{
try
{
var logger = conLogger.GetLogger("AAA");
if (logger == null)
{
Console.WriteLine(string.Format("弟{0}个线程获取到的值是 NULL", o));
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("弟{0}个线程出现问题, {1}", o, ex.Message));
}
});
}); Console.WriteLine("已执行完成");
Console.ReadKey();
}

用Release模式编译之后,测试的结果:

第一次:

第二次:

第三次:

总结:

从测试结果来看,都解决了我们上述的问题,总体的时间比值来看ConcurrentDictionary稍微优于LockDictionary, 但是差别不是很大, 第一次几乎持平.

写代码还是要多注意线程安全的问题。

 

上面的CodeTimer用的是: http://www.cnblogs.com/JeffreyZhao/archive/2009/03/10/codetimer.html

多线程环境下非安全Dictionary引起的“已添加了具有相同键的项”问题的更多相关文章

  1. System.ArgumentException: 已添加了具有相同键的项。(An item with the same key has already been added) 在 System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) 在 System.Web.Mvc.Js

    最近将一个项目从ASP.NET MVC 3升级至刚刚发布的ASP.NET MVC 5.1,升级后发现一个ajax请求出现了500错误,日志中记录的详细异常信息如下: System.ArgumentEx ...

  2. SQLite在多线程环境下的应用

    文一 SQLite的FAQ里面已经专门说明,先贴出来.供以后像我目前的入门者学习. (7) 多个应用程序或者同一个应用程序的多个例程能同时存取同一个数据库文件吗? 多进程可以同时打开同一个数据库,也可 ...

  3. 你是否听说过 HashMap 在多线程环境下操作可能会导致程序死循环?

    作者:炸鸡可乐 原文出处:www.pzblog.cn 一.问题描述 经常有些面试官会问,是否了解过 HashMap 在多线程环境下使用时可能会发生死循环,导致服务器 cpu 100% 的线上故障? 关 ...

  4. Java指令重排序在多线程环境下的应对策略

    一.序言 指令重排在单线程环境下有利于提高程序的执行效率,不会对程序产生负面影响:在多线程环境下,指令重排会给程序带来意想不到的错误. 本文对多线程指令重排问题进行复原,并针对指令重排给出相应的解决方 ...

  5. C#多线程环境下调用 HttpWebRequest 并发连接限制

    C#多线程环境下调用 HttpWebRequest 并发连接限制 .net 的 HttpWebRequest 或者 WebClient 在多线程情况下存在并发连接限制,这个限制在桌面操作系统如 win ...

  6. C++多线程环境下的构造函数

    多线程的环境里,我们总不可避免要使用锁.于是一个常见的场景就是: class ObjectWithLock { private: std::mutex mtx_; SomeResType shared ...

  7. Asp.Net在多线程环境下的状态存储问题

    在应用开发中,我们经常需要设置一些上下文(Context)信息,这些上下文信息一般基于当前的会话(Session),比如当前登录用户的个人信息:或者基于当前方法调用栈,比如在同一个调用中涉及的多个层次 ...

  8. HttpClient在多线程环境下踩坑总结

    问题现场 在多线程环境下使用HttpClient组件对某个HTTP服务发起请求,运行一段时间之后发现客户端主机CPU利用率呈现出下降趋势,而不是一个稳定的状态. 而且,从程序日志中判断有线程处于han ...

  9. 多线程环境下的UI异步操作

    转自原文 多线程环境下的UI异步操作 解决VS中,线程间不可互操作的问题,一揽子解决方案: 一.首先,定义一个类:SetControlProperty using System.Reflection; ...

随机推荐

  1. 无限树Jquery插件zTree的使用方法

    其实Ztree官网已经有详细的API文档,一切以官网上的说明为准,我在此只是结合实践总结几条常用的ztree的功能特性. (ztree的语法结构是基于key-value的形式配置) 1:支持异步加载数 ...

  2. 1001 数组中和等于K的数对 1002 数塔取数问题 1003 阶乘后面0的数量 1004 n^n的末位数字 1009 数字1的数量

    1001 数组中和等于K的数对 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 给出一个整数K和一个无序数组A,A的元素为N个互不相同的整数,找出数组A中所有和等于K ...

  3. Max Consecutive Ones

    Given a binary array, find the maximum number of consecutive 1s in this array. Example 1: Input: [1, ...

  4. .Neter玩转Linux系列之六:Linux下MySQL的安装、配置、使用

    一.Linux安装MySQL (1)下载安装包:https://dev.mysql.com/downloads/mysql/ (2)解压并安装 命令:tar zxvf 文件名 解压完成之后,重名一下文 ...

  5. 微信小程序的跨平台图表库开发

    写在前面 微信小程序出来已经有一段时间了,github上也有很多人开源了很多项目.但是由于微信平台的限制(底层Canvas能力调用为一系列JSBridge封装),图表的制作一直是个比较头疼的问题.当前 ...

  6. Ubuntu12.04 Firefox安装flash

    1. 实验环境 Ubuntu 14.04x86 2.安装步骤 2.1 浏览器访问:https://get.adobe.com/flashplayer/?loc=cn 2.2 网址会自动识别ubuntu ...

  7. ZOJ2006 一道很尴尬的string操作题

    ZOJ2006(最小表示法) 题目大意:输出第一个字符串的最小字典序字串的下标! 然后我居然想试一试string的erase的能力,暴力一下,然后20msAC了,尴尬的数据.......... #in ...

  8. PPT的应用

    ppt是Office中一个制作演示文稿的一个办公软件使阐述过程简明而又清晰,轻松又丰富详实,从而有效表达自己以及与他人沟通,所创建的文件被称为电子演示文稿,其扩展名为.PPT.一个演示文稿由若干张电子 ...

  9. JavaScript函数之实际参数对象(arguments) / callee属性 / caller属性 / 递归调用 / 获取函数名称的方法

    函数的作用域:调用对象 JavaScript中函数的主体是在局部作用域中执行的,该作用域不同于全局作用域.这个新的作用域是通过将调用对象添加到作用域链的头部而创建的(没怎么理解这句话,有理解的亲可以留 ...

  10. [NOIP2014][DP]飞扬的小鸟

    [NOIP2014]飞扬的小鸟 ——!x^n+y^n=z^n 题目描述: Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画 ...