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.
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
Framework 4.0 provides a set of new collections in the
System.Collections.Concurrent namespace. All of these are fully thread-safe:
In the IProducerConsumerCollection<T> interface defines
methods to manipulate
thread-safe collections intended for producer/consumer
producer/consumer collections which is
the two primary use cases. These are:
- Adding an element (“producing”)
- Retrieving an element
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
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.
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
we use BlockingCollection<T> (exception handling aside)
in a program:
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());
// An InvalidOperationException means that Take() was called on a completed
Console.WriteLine("That's All. Everything is Ok!");
static void Main()
Console.WriteLine(@" Let's try to use Concurrent collection");
Because we didn’t pass anything into Blocking Collection’s constructor, it instantiated a concurrent
For details we see also:
Programming in C#