国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

多線程環境下非安全Dictionary引起的“已添加了具有相同鍵的項”問題

2019-11-14 13:56:41
字體:
來源:轉載
供稿:網友

問題:

代碼是在多線程環境下,做了簡單的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的地方做了判斷的處理,但是在多線程的時候還是會出現在取的時候取不到的問題??梢詤⒖枷旅娼貓D :

image

從錯誤異常很容易判斷,是在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模式編譯之后,測試的結果:

第一次:

image

第二次:

image

第三次:

image

總結:

從測試結果來看,都解決了我們上述的問題,總體的時間比值來看ConcurrentDictionary稍微優于LockDictionary, 但是差別不是很大, 第一次幾乎持平.

寫代碼還是要多注意線程安全的問題。

 

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


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 金塔县| 普宁市| 潢川县| 双城市| 彩票| 潢川县| 茶陵县| 永登县| 高淳县| 长葛市| 乌兰浩特市| 咸阳市| 西峡县| 桃江县| 广州市| 太保市| 霍州市| 安泽县| 自治县| 湖北省| 平乐县| 无为县| 稻城县| 新乐市| 全州县| 梁河县| 江山市| 石渠县| 伽师县| 康保县| 襄垣县| 唐山市| 巩留县| 河北省| 耿马| 渭南市| 邢台县| 平阴县| 清涧县| 北辰区| 鹰潭市|