Concurrent Collections in C#

In C#, traditional collection classes are using with a lock, but concurrent collection classes are lock free. So, it will often use in parallel programming for performance concern. ConcurrentDictionary runs three times faster than Dictionary.

The concurrent collections can sometimes be useful in general multithreading when we need a thread-safe collection. However, there are some conditions:

  • The concurrent collections are using in highly concurrent scenarios.
  • A thread-safe collection doesn’t guarantee that the code using it will be thread-safe.
  • If we enumerate over a concurrent collection while another thread is modifying it, no exception is thrown.
  • There’s no concurrent version of List<T> in concurrent collections.
  • The concurrent stack, queue, and bag classes are implemented internally with linked lists.

In Framework 4.0 provides a set of new collections in the System.Collections.Concurrent namespace. All of these are fully thread-safe:


·         ConcurrentStack<T>

·         ConcurrentQueue<T>

·         ConcurrentBag<T>

·         BlockingCollection<T>

·         ConcurrentDictionary<Tkey,TValue>




In the IProducerConsumerCollection<T> interface defines methods to manipulate thread-safe collections intended for producer/consumer usage. A producer/consumer collections which is the two primary use cases. These are:

  • Adding an element (“producing”)
  • Retrieving an element (“consuming”)

The IProducerConsumerCollection<T> interface are implementing three classes these are follows:




 This interface also extends ICollection interface for adding the following methods:


bool TryAdd (T item);

bool TryTake (out T item);


The TryAdd and TryTake methods test add and remove operation for eliminating the need of lock. If the collection is empty TryTake returns false otherwise, TryAdd always succeeds and returns true.


ConcurrentBag<T> stores an unordered collection of objects (it allows duplicates contents). ConcurrentBag<T>  is prefer in situations when we do not care which element we get when calling TryTake or Take.

The benefit of  ConcurrentBag<T> over a concurrent queue or stack is that a bag’s Add method suffers almost no contention when called by many threads at once. A concurrent bag would be a poor choice for a producer/consumer queue, because elements are added and removed by different threads.


If we call TryTake on any of the producer/consumer collections we discussed previously and the collection is empty, the method returns false. Sometimes it would be more useful in this scenario to wait until an element is available. Rather than overloading the TryTake methods

Here we use BlockingCollection<T> (exception handling aside) in a program:

class AddTakeDemo
{   public static void BC_AddTakeCompleteAdding()   {      using (BlockingCollection<string> bc = new BlockingCollection<string>())
            // Spin up a Task to populate the BlockingCollection
            using (Task t1 = Task.Factory.StartNew(() =>
                for (int i = 1; i <=10; i++)
                    bc.Add("HI Guest "+i);
                // Spin up a Task to consume the BlockingCollection
                using (Task t2 = Task.Factory.StartNew(() =>
                        // Consume consume the BlockingCollection
                        while (true) Console.WriteLine(bc.Take());
                    catch (InvalidOperationException)
                        // An InvalidOperationException means that Take() was called on a completed collection
                        Console.WriteLine("That's All. Everything is Ok!");
                    Task.WaitAll(t1, t2);
            }   }    }
class BlockingCollectionEx
{    static void Main() {   Console.WriteLine(@" Let's try to use Concurrent collection");
   AddTakeDemo.BC_AddTakeCompleteAdding();       Console.ReadKey();    }



Because we didn’t pass anything into Blocking Collection’s constructor, it instantiated a concurrent queue automatically.

For details we see also:

·         Parallel Programming in C#

·         Synchronization in C#




Leave Comment