System.Collections.Concurrent 命名空間提供多個線程安全集合類。算法
當有多個線程併發訪問集合時,應使用這些類代替 System.Collections 和 System.Collections.Generic 命名空間中的對應類型。數組
爲了對集合進行線程安全的訪問,定義了 IProducerConsumerCollection<T>接口。這個接口中最重 要的方法是TryAdd()和TryTake()。
TryAdd()方法嘗試給集合添加一項,但若是集合禁止添加項,這個操做就可能失敗。爲了給出相關信息,TryAdd()方法返回一個布爾值,以說明操做是成功仍是失敗。安全
TryTake()方法也以這種方式工做,以通知調用者操做是成功仍是失敗,並在操做成功時返回集合中的項。併發
下面列出了 SystemCollections.Concurrent名稱空間中的類及其功能:函數
這個集合類用一種免鎖定的算法實現,使用在內部合併到一個鏈表中的32項數組。
訪問隊列元素的方法有Enqueue()、TryDequeue()和TryPeek()。這些方法的命名很是相似於前面Queue<T>類的方法,只是給可能調用失敗的方法加上了前綴Try。 由於這個類實現了IProducerConsumerCollection<T>接口,因此 TryAdd()和 TryTake()方法僅調用 Enqueue()和 TryDequeue()方法。spa
很是相似於ConcurrentQueue<T>類,只是帶有另外的元素訪問方法。
ConcurrcntStack<T>類定義了 Push()、PushRange()、TryPeek()、TiyPop()和 TryPopRange() 方法。在內部這個類使用其元素的鏈表。線程
該類沒有定義添加或提取項的任何順序。這個類使用一個把線程映射到內部使用的數組上的概念,所以嘗試減小鎖定。訪問元素的方法有Add()、TryPeek()和 TryTake()。code
——這是一個線程安全的鍵值集合。
TryAdd()、TryGetValue()、TryRemove()和TryUpdate()方法以非阻塞的方式訪問成員。
由於元素基於鍵和值, 因此 ConcurrentDictionary<TKey,TValue>沒有實現 IProducerConsumerCollection<T>。blog
這些集合是線程安全的,若是某個動做不適用於線程的當前狀態,它們就返回fclse。在繼續以前,老是霈要確認添加或提取元素是否成功。不能相信集合會完成任務。接口
這個集合在能夠添加或提取元素以前,會阻塞線程並一直等待。 BlockingCollection<T>集合提供了一個接口,以使用Add()和Take()方法來添加和刪除元素。 這些方法會阻寒線程,一直等到任務能夠執行爲止。
Add()方法有一個重載版本,其中能夠給該重載版本傳遞一個CancellationToken令牌。這個令牌容許取消被阻塞的調用。若是不但願線程無限期地等待下去,且不但願從外部取消調用,就能夠使用TryAdd()和 TryTake()方法,在這些方法中,也能夠指定一個超時值,它表示在調用失敗以前應阻塞線程和等待的最長時間。
這是對實現了 IProducerConsumerCollection<T>接口的任意類的修飾器,它默認使用ConcurrentQueue<T>類。還能夠給構造函數傳遞任何其餘實現了 IProducerConsumerCollection<T> 接口的類。
下面的代碼示例簡單演示了使用BlockingCollection<T>類和多個線程的過程。一個線程是生成器,它使用Add()方法給集合寫入元素,另外一個線程是使用者,它使用Take()方法從集合中提取元素:
internal static BlockingCollection<int> _TestBCollection; class ThreadWork1 // producer { public ThreadWork1() { } public void run() { System.Console.WriteLine("ThreadWork1 run { "); for (int i = 0; i < 100; i++) { System.Console.WriteLine("ThreadWork1 producer: " + i); _TestBCollection.Add(i); } _TestBCollection.CompleteAdding(); System.Console.WriteLine("ThreadWork1 run } "); } } class ThreadWork2 // consumer { public ThreadWork2() { } public void run() { int i = 0; int nCnt = 0; bool IsDequeuue = false; System.Console.WriteLine("ThreadWork2 run { "); while (!_TestBCollection.IsCompleted) { IsDequeuue = _TestBCollection.TryTake(out i); if (IsDequeuue) { System.Console.WriteLine("ThreadWork2 consumer: " + i * i + " =====" + i); nCnt++; } } System.Console.WriteLine("ThreadWork2 run } "); } } static void StartT1() { ThreadWork1 work1 = new ThreadWork1(); work1.run(); } static void StartT2() { ThreadWork2 work2 = new ThreadWork2(); work2.run(); } static void Main(string[] args) { Task t1 = new Task(() => StartT1()); Task t2 = new Task(() => StartT2()); _TestBCollection = new BlockingCollection<int>();//能夠跟容量 Console.WriteLine("Sample 4-4 Main {"); Console.WriteLine("Main t1 t2 started {"); t1.Start(); t2.Start(); Console.WriteLine("Main t1 t2 started }"); Console.WriteLine("Main wait t1 t2 end {"); Task.WaitAll(t1, t2); Console.WriteLine("Main wait t1 t2 end }"); Console.WriteLine("Sample 4-4 Main }"); }