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

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

多線程下的集合安全

2019-11-17 02:52:59
字體:
來源:轉載
供稿:網友

多線程下的集合安全

2014-09-18 10:32 by 遲來的春天, ... 閱讀, ... 評論, 收藏, 編輯

在多線程內使用集合,如果未對集合做任何安全處理,就非常容易出現系統崩潰或各種錯誤。最近的項目里,使用的是socket通信后再改變了某個集合,結果導致系統直接崩潰,且無任何錯誤系統彈出。

經排查,發現問題是執行某集合后,系統就會在一定時間內退出,最后發現是使用的一個字典集合出了問題。稍微思考后,就認定了是線程安全問題。因為此集合在其它幾個地方都有線程做循環讀取。

下面是我模擬的一個示例,沒有進行任何的安全處理:

 1 class PRogram 2     { 3         static MyCollection mycoll; 4         static void Main(string[] args) 5         { 6             mycoll = new MyCollection(); 7             Thread readT = new Thread(new ThreadStart(ReadMethod)); 8             readT.Start(); 9 10             Thread addT = new Thread(new ThreadStart(AddMethod));11             addT.Start();12             Console.ReadLine();13         }14         public static void AddMethod()15         {16             for(int i=0;i<10;i++)17             {18                 Thread.Sleep(500);19                 mycoll.Add("a"+i, i);20             }21         }22         public static void ReadMethod()23         {24             while (true)25             {26                 Thread.Sleep(100);27                 foreach (KeyValuePair<string, int> item in mycoll.myDic)28                 {29                     Console.WriteLine(item.Key + "http://t" + item.Value);30                     //其它處理31                     Thread.Sleep(2000);32                 }33             }34         }35     }36     public class MyCollection37     {38         public Dictionary<string, int> myDic = new Dictionary<string, int>();39 40         public void Add(string key, int value)41         {42             if (myDic.ContainsKey(key))43             {44                 myDic[key] += 1;45             }46             else47             {48                 myDic.Add(key, value);49             }50         }51 52         public void Remove(string key)53         {54             if (myDic.ContainsKey(key))55             {56                 myDic.Remove(key);57             }58         }59     }

在上面的示例中,創建了一個Dictionary字典對像,程序運行時,輸出了下面的錯誤:

程序運行時,輸出了上面的錯誤,僅僅輸出了一行結果

這次測試有明顯示的錯誤提示,集合已修改;可能無法執行枚舉操作。

唉,真是一個常見的問題,在foreach的時侯又修改集合,就一定會出現問題了,因為foreach是只讀的,在進行遍歷時不可以對集合進行任何修改。

看到這里,我們會想到,如果使用for循環進行逆向獲取,也許可以解決此問題。

非常可惜,字典對像沒有使用索引號獲取的辦法,下面的表格轉自(http://m.survivalescaperooms.com/yang_sy/p/3678905.html)

Type內部結構支持索引內存占用隨機插入的速度(毫秒)順序插入的速度(毫秒)根據鍵獲取元素的速度(毫秒)
未排序字典
Dictionary<T,V>哈希表22303020
Hashtable哈希表38505030
ListDictionary鏈表36500005000050000
OrderedDictionary哈希表 +數組59707040
排序字典
SortedDictionary<K,V>紅黑樹20130100120
SortedList<K,V>2xArray2033003040
SortList2xArray274500100180

從時間復雜度來講,從字典中通過鍵獲取值所耗費的時間分別如下:

  • Hashtable, Dictionary和OrderedDictionary的時間復雜度為O(1)
  • SortedDictionary和SortList的時間復雜度為O(logN)
  • ListDictinary的時間復雜度為O(n)

這可如何是好,只能改為可排序的對像?然后使用for解決?

我突然想到,是否可以在循環時縮短foreach,來解決此問題呢?

想到可以在循環時先copy一份副本,然后再進行循環操作,編寫代碼,查找copy的方法。真是無奈,沒有提供任何的copy方法。唉!看來人都是用來被逼的,先改個對象吧:

把Dictionary修改成了Hashtable對像(也沒有索引排序)。代碼如下:

 1  class Program 2     { 3         static MyCollection mycoll; 4         static void Main(string[] args) 5         { 6             mycoll = new MyCollection(); 7             Thread readT = new Thread(new ThreadStart(ReadMethod)); 8             readT.Start(); 9 10             Thread addT = new Thread(new ThreadStart(AddMethod));11             addT.Start();12             Console.ReadLine();13         }14         public static void AddMethod()15         {16             for(int i=0;i<10;i++)17             {18                 Thread.Sleep(500);19                 mycoll.Add("a"+i, i);20             }21         }22         public static void ReadMethod()23         {24             while (true)25             {26                 Thread.Sleep(100);27                 foreach (DictionaryEntry item in mycoll.myDic)28                 {29                     Console.WriteLine(item.Key + "      " + item.Value);30                     //其它處理31                     Thread.Sleep(2000);32                 }33             }34         }35     }36     public class MyCollection37     {38         public Hashtable myDic = new Hashtable();39         40         public void Add(string key, int value)41         {42             if (myDic.ContainsKey(key))43             {44                 45                 myDic[key] =Convert.ToInt32(myDic[key])+ 1;46             }47             else48             {49                 myDic.Add(key, value);50             }51         }52 53         public void Remove(string key)54         {55             if (myDic.ContainsKey(key))56             {57                 myDic.Remove(key);58             }59         }60     }

代碼一如即往的報錯,錯誤信息一樣。使用copy法試試

 1 class Program 2     { 3         static MyCollection mycoll; 4         static void Main(string[] args) 5         { 6             mycoll = new MyCollection(); 7             Thread readT = new Thread(new ThreadStart(ReadMethod)); 8             readT.Start(); 9 10             Thread addT = new Thread(new ThreadStart(AddMethod));11             addT.Start();12             Console.ReadLine();13         }14         public static void AddMethod()15         {16             for(int i=0;i<10;i++)17             {18                 Thread.Sleep(500);19                 mycoll.Add("a"+i, i);20             }21         }22         public static void ReadMethod()23         {24             Hashtable tempHt = null;25             while (true)26             {27                 Thread.Sleep(10
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 古田县| 泉州市| 海原县| 全椒县| 宜阳县| 葫芦岛市| 平邑县| 阿拉尔市| 商洛市| 马边| 上栗县| 丽水市| 屏南县| 南安市| 威宁| 白河县| 古蔺县| 神农架林区| 连云港市| 伽师县| 吉安市| 平江县| 兴隆县| 宜城市| 温泉县| 秀山| 登封市| 北碚区| 都兰县| 靖西县| 酒泉市| 徐州市| 新沂市| 文山县| 兴安县| 密山市| 梁山县| 尼勒克县| 房山区| 石台县| 新乡市|