安全字典ConcurrentDictionary的一个使用误区ContainsKey

ConcurrentDictionary的ContainsKey 保证了多线程读取、写入没问题,线程安全。但是并不能保证Key 重复 。这里多线程的时候,Key可能重复导致Add失败,请优先使用 AddOrUpdate 。

 

using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Reflection;

namespace MulThreadTest
{

 //下面的示范是一个并发插入错误的写法。
///方案1:加锁--lock (ReaderWriterLockSlim);方案2:使用TryAddOrUpdate
    class MainClass
    {
        public static void Main (string[] args)
        {

    
            var dic = new ConcurrentDictionary<int,int> ();


            for (int i = 0; i < 10; i++) {
                
                var th = new Thread (new ParameterizedThreadStart ((state) => {

                    var num = DoHelper.Instance.SayHello ();

                    if (dic.ContainsKey (num)) {
                        dic.AddOrUpdate (num, num, (m, n) => {
                            return n;
                        });
                        Console.WriteLine ("AddOrUpdate: " + num.ToString ());

                    } else {
                        var addRes = dic.TryAdd (num, num);

                        if (false == addRes) {
                            Console.WriteLine ("Error add. num exits");
                        }
                    }
                }));    


                th.Start (i);
            }

            Console.ReadKey ();

        }




    }



    public class DoHelper
    {

        public static DoHelper Instance = new DoHelper ();

        public int SayHello ()
        {
             
            var num = new Random (DateTime.Now.Millisecond).Next ();

            return num;
             
        }
    
    }
}

加锁:

 1 using System;
 2 using System.Collections.Concurrent;
 3 using System.Threading;
 4 using System.Threading.Tasks;
 5 using System.Diagnostics;
 6 using System.Reflection;
 7 
 8 namespace MulThreadTest
 9 {
10     class MainClass
11     {
12         public static void Main (string[] args)
13         {
14 
15              
16             var dic = new ConcurrentDictionary<int,int> ();
17 
18             var    _locker = new ReaderWriterLockSlim ();
19 
20             for (int i = 0; i < 5; i++) {
21                 
22                 var th = new Thread (new ParameterizedThreadStart ((state) => {
23 
24 
25                     for (int yy = 0; yy < 20; yy++) {
26                         
27                     
28                         var num = DoHelper.Instance.SayHello ();
29 
30                     
31                         _locker.TryEnterWriteLock (TimeSpan.FromSeconds (10));
32                      
33 
34                         if (dic.ContainsKey (num)) {
35                             dic.AddOrUpdate (num, num, (m, n) => {
36                                 return n;
37                             });
38                             Console.WriteLine ("AddOrUpdate: " + num.ToString ());
39 
40                         } else {
41                             var addRes = dic.TryAdd (num, num);
42 
43 
44 
45                             if (false == addRes) {
46                                 throw new Exception ("Error add. num exits:" + num.ToString ());
47                             } else {
48                                 Console.WriteLine ("TryAdd: " + num.ToString ());
49                             }
50                         }
51 
52                         _locker.ExitWriteLock ();
53 
54                     
55                     }
56 
57 
58 
59                 }));    
60 
61 
62                 th.Start (i);
63             }
64 
65              
66 
67             Console.ReadKey ();
68 
69         }
70 
71 
72 
73 
74     }
75 
76 
77 
78     public class DoHelper
79     {
80 
81         public static DoHelper Instance = new DoHelper ();
82 
83         public int SayHello ()
84         {
85              
86             var num = new Random (DateTime.Now.Millisecond).Next ();
87 
88             return num;
89              
90         }
91     
92     }
93 }
View Code

AddOrUpdate:

 1 using System;
 2 using System.Collections.Concurrent;
 3 using System.Threading;
 4 using System.Threading.Tasks;
 5 using System.Diagnostics;
 6 using System.Reflection;
 7 
 8 namespace MulThreadTest
 9 {
10     class MainClass
11     {
12         public static void Main (string[] args)
13         {
14 
15              
16             var dic = new ConcurrentDictionary<int,int> ();
17 
18              
19 
20             for (int i = 0; i < 5; i++) {
21                 
22                 var th = new Thread (new ParameterizedThreadStart ((state) => {
23 
24 
25                     for (int yy = 0; yy < 10; yy++) {
26                         
27                     
28                         var num = DoHelper.Instance.SayHello ();
29 
30 
31                             dic.AddOrUpdate (num, num, (key, old) => {
32                                 //your update logic
33                                 return old;
34                             });
35                          
36 
37                         Console.WriteLine ("AddOrUpdate: "+num);
38 
39                     
40                     }
41 
42 
43 
44                 }));    
45 
46 
47                 th.Start (i);
48             }
49 
50              
51 
52             Console.ReadKey ();
53 
54         }
55 
56 
57 
58 
59     }
60 
61 
62 
63     public class DoHelper
64     {
65 
66         public static DoHelper Instance = new DoHelper ();
67 
68         public int SayHello ()
69         {
70              
71             var num = new Random (DateTime.Now.Millisecond).Next ();
72 
73             return num;
74              
75         }
76     
77     }
78 }
View Code

 

参考:

https://referencesource.microsoft.com/#mscorlib/system/Collections/Concurrent/ConcurrentDictionary.cs,4d0f4ac22dbeaf08


 

 

 

 

 

 

using System;using System.Collections.Concurrent;using System.Threading;using System.Threading.Tasks;using System.Diagnostics;using System.Reflection;
namespace MulThreadTest{class MainClass{public static void Main (string[] args){
 var dic = new ConcurrentDictionary<int,int> ();
 
for (int i = 0; i < 5; i++) {var th = new Thread (new ParameterizedThreadStart ((state) => {

for (int yy = 0; yy < 10; yy++) {var num = DoHelper.Instance.SayHello ();

dic.AddOrUpdate (num, num, (key, old) => {    //your update logicreturn old;}); 
Console.WriteLine ("AddOrUpdate: "+num);
}


}));

th.Start (i);}
 
Console.ReadKey ();
}



}


public class DoHelper{
public static DoHelper Instance = new DoHelper ();
public int SayHello (){             var num = new Random (DateTime.Now.Millisecond).Next ();
return num; }}}

 

posted @ 2021-04-28 12:05  特洛伊-Micro  阅读(401)  评论(0编辑  收藏  举报