原文转载自:http://www.cnblogs.com/xray2005/archive/2011/10/11/2206745.html
在.Net 4中,新增System.Collections.Concurrent 命名空间中提供多个线程安全集合类,这些类提供了很多有用的方法用于访问集合中的元素,从而可以避免使用传统的锁(lock)机制等方式来处理并发访问集合.因此当有多个线程并发访问集合时,应首先考虑使用这些类代替 System.Collections 和 System.Collections.Generic 命名空间中的对应类型.具体如下:
1. ConcurrentQueue
表示线程安全的先进先出(FIFO)队列.代码如下:
ConcurrentQueue<int> sharedQueue = new ConcurrentQueue<int>(); for (int i = ; i < ; i++) { sharedQueue.Enqueue(i); } int itemCount = ; Task[] tasks = new Task[]; for (int i = ; i < tasks.Length; i++) { tasks[i] = new Task(() => { while (sharedQueue.Count > ) { int queueElement; bool gotElement = sharedQueue.TryDequeue(out queueElement); if (gotElement) { Interlocked.Increment(ref itemCount); } } }); tasks[i].Start(); } Task.WaitAll(tasks); Console.WriteLine("Items processed:{0}", itemCount); Console.WriteLine("Press Enter to finish"); Console.ReadLine();
该类有两个重要的方法用来访问队列中的元素.分别是:
Ø TryDequeue 尝试移除并返回位于队列头开始处的对象.
Ø TryPeek尝试返回位于队列头开始处的对象但不将其移除.
现在,在多任务访问集合元素时,我们只需要使用TryDequeue或TryPeek方法,就可以安全的访问集合中的元素了.
2. ConcurrentStack
表示线程安全的后进先出(LIFO)栈.它也有几个有用的方法,分别是:
Ø TryPeek:尝试返回栈顶处的元素,但不移除.
Ø TryPop: 尝试返回栈顶处的元素并移除.
Ø TryPopRange: 尝试返回栈顶处开始指定范围的元素并移除.
在访问集合中的元素时,我们就可以上述方法.具体代码实例于上面的ConcurrentQueue类似,就不重复了.
3. ConcurrentBag
实现的是一个无序的集合类.代码如下:
ConcurrentBag<int> sharedBag = new ConcurrentBag<int>(); for (int i = ; i < ; i++) { sharedBag.Add(i); } int itemCount = ; Task[] tasks = new Task[]; for (int i = ; i < tasks.Length; i++) { tasks[i] = new Task(() => { while(sharedBag.Count>) { int queueElement; bool gotElement = sharedBag.TryTake(out queueElement); if (gotElement) Interlocked.Increment(ref itemCount); } }); tasks[i].Start(); } Task.WaitAll(tasks); Console.WriteLine("Items processed:{0}", itemCount); Console.WriteLine("Press Enter to finish"); Console.ReadLine();
该类有两个重要的方法用来访问队列中的元素.分别是:
Ø TryTake 尝试移除并返回位于队列头开始处的对象.
Ø TryPeek尝试返回位于队列头开始处的对象但不将其移除.
4. ConcurrentDictionary
实现的是一个键-值集合类.它提供的方法有:
Ø TryAdd:尝试向集合添加一个键-值
Ø TryGetValue:尝试返回指定键的值.
Ø TryRemove:尝试移除指定键处的元素.
Ø TryUpdate:尝试更新指定键的值.
代码如下:
class BankAccount { public int Balance { get; set; } } static void DictTest() { BankAccount account = new BankAccount(); ConcurrentDictionary<object, int> sharedDict = new ConcurrentDictionary<object, int>(); Task<int>[] tasks = new Task<int>[]; for (int i = ; i < tasks.Length; i++) { sharedDict.TryAdd(i, account.Balance); tasks[i] = new Task<int>((keyObj) => { int currentValue; bool gotValue; for (int j = ; j < ; j++) { gotValue = sharedDict.TryGetValue(keyObj, out currentValue); sharedDict.TryUpdate(keyObj, currentValue + , currentValue); } int result; gotValue = sharedDict.TryGetValue(keyObj, out result); if (gotValue) { return result; } else { throw new Exception(String.Format("No data item available for key {0}", keyObj)); } }, i); tasks[i].Start(); } for (int i = ; i < tasks.Length; i++) { account.Balance += tasks[i].Result; } Console.WriteLine("Expected value {0}, Balance: {1}", , account.Balance); Console.WriteLine("Press enter to finish"); Console.ReadLine(); }
通过上述提供的安全类,我们可以方便的并发访问集合中的元素,而不需要以前的Synchronized方法或者lock(SyncRoot)等处理方式.