Working with Concurrent Collections in .NET Framework 4.0 | CodeGuru

Working with Concurrent Collections in .NET Framework 4.0

Concurrent collections in .NET Framework 4.0 allow the developers to create type safe as well as thread safe collections. These collection classes form an essential part of the parallel programming feature and are available under the namespace System.Collections.Concurrent. Below are the different types of concurrent collections. 1. ConcurrentDictionary 2. ConcurrentStack 3. ConcurrentQueue 4. ConcurrentBag […]

Written By
CodeGuru Staff
CodeGuru Staff
Mar 20, 2012
2 minute read
CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More

Concurrent collections in .NET Framework
4.0 allow the developers to create type safe as well as thread safe
collections. These collection classes form an essential part of the parallel
programming feature and are available under the namespace System.Collections.Concurrent.
Below are the different types of concurrent collections.

1. ConcurrentDictionary<TKey,
TValue>
2. ConcurrentStack<T>
3. ConcurrentQueue<T>
4. ConcurrentBag<T>
5. BlockingCollection<T>

The producer and consumer
pattern can easily be implemented while using ConcurrentStack, ConcurrentQueue
and ConcurrentBag as they implement the interface IProducerConsumerCollection.

Need for Concurrent Collections

Though
System.Collections namespace offers a wide range of collections, the only thing
which limits our use of them in a multi-threaded or parallel environment is
that they are not thread-safe. A non thread-safe collection will lead to
race conditions and throw unexpected exceptions. In order to make them thread
safe, a locking mechanism should be implemented as shown in the example below.

Dictionary<string, string> _dictionaryCollection = new Dictionary<string, string>();
object _lockingObject = new object();
public void AddToCollection(string key, string value)
{
            lock (_lockingObject)
            {
                _dictionaryCollection.Add(key, value);
            }
}
 

The above code will work fine in
a multi-threaded operation but it is a little costly in terms of performance,
since it blocks all the other threads until the current thread exits the lock.
This is why concurrent collections are required. Concurrent collections can be
shared across multiple threads with no explicit locks and it also increases the
scalability and performance of multi-threaded operations.

ConcurrentDictionary

ConcurrentDictionary is used to
create a thread-safe key value pair. It offers several methods, such as TryAdd,
TryGetValue, AddOrUpdate, etc. All these methods are thread-safe. Below is the
sample code for using ConcurrentDictionary.

class Program
{
 
    static void Main(string[] args)
    {
        //Consider this as a list from database which is huge and we need to represent this data as a keyvalue pair using ConcurrentDictionary
        string[] techWebSites = new string[] { "www.codeguru.com", "www.internet.com", "www.devx.com", "www.developer.com" };
 
        Task[] taskList = new Task[2];
 
        ConcurrentDictionary<int, string> dictionaryWebsites = new ConcurrentDictionary<int, string>();
 
        //With the creation of two tasks we have divided the load of populating the collection byt without doing any explicit synchronization
        taskList[0] = Task.Factory.StartNew(() =>
            {
                for (int i = 0; i < techWebSites.Length; i++)
                {
                    if (dictionaryWebsites.TryAdd(i, techWebSites[i]))
                        Console.WriteLine("Website {0} added to the dictionary!", techWebSites[0]);
                }
            });
 
        taskList[1] = Task.Factory.StartNew(() =>
        {
            for (int i = 0; i < techWebSites.Length; i++)
            {
                if (dictionaryWebsites.TryAdd(i, techWebSites[i]))
                    Console.WriteLine("Website {0} added to the dictionary!", techWebSites[0]);
            }
        });
 
        Task.WaitAll();
 
    }
}
Advertisement

ConcurrentQueue

ConcurrentQueue is a thread-safe
first in first out (FIFO) collection. The code below is using ConcurrentQueue
in a multi-threaded operation.

class Program
{
    static void Main(string[] args)
    {
        ConcurrentQueue<string> nameCollection = new ConcurrentQueue<string>();
        nameCollection.Enqueue("Adam Hollioke");
        nameCollection.Enqueue("Ben Hollioke");
        nameCollection.Enqueue("Ronie Irani");
        nameCollection.Enqueue("Patrick");
        nameCollection.Enqueue("Stuart Clarke");
        nameCollection.Enqueue("Mike Gatting");
 
        Task[] taskList = new Task[2];
 
        taskList[0] = Task.Factory.StartNew(() =>
            {
                string name = String.Empty;
                while (nameCollection.TryDequeue(out name))
                    Console.WriteLine("Name {0} is dequeued!", name);
            });
 
        taskList[1] = Task.Factory.StartNew(() =>
        {
            string name = String.Empty;
            while (nameCollection.TryDequeue(out name))
                Console.WriteLine("Name {0} is dequeued!", name);
        });
 
        Task.WaitAll();
        Console.ReadLine();
    }
}

ConcurrentStack

ConcurrentStack is a thread-safe
collection to perform last in first out (LIFO) operations. The code below demonstrates
the use of ConcurrentStack.

class Program
{
    static void Main(string[] args)
    {
        ConcurrentStack<int> numberCollection = new ConcurrentStack<int>();
        for (int i = 10; i <= 20; i++)
        {
            numberCollection.Push(i);
        }
 
        Parallel.For(0, 10, i =>
            {
                int value = 0;
                if (numberCollection.TryPop(out value))
                    Console.WriteLine("Value {0} is popped out!", value);
            });
 
        Console.ReadLine();
    }
}

A range of values can be pushed into
or popped out from the ConcurrentStack using the methods PushRange and
TryPopRange.

Advertisement

ConcurrentBag

ConcurrentBag is used to maintain
the list of unordered items. TryTake and TryPeek methods can be used it take
the item out of the bag and to peek for the value in the bag respectively.
Below is the sample code to use ConcurrentBag.

class Program
{
    static ConcurrentBag<string> _entityCollection = new ConcurrentBag<string>();
    static void Main(string[] args)
    {
        _entityCollection.Add("Company1");
        _entityCollection.Add("Catalog1");
        _entityCollection.Add("Order1");
        _entityCollection.Add("Company2");
        _entityCollection.Add("Catalog2");
        _entityCollection.Add("Order2");
        _entityCollection.Add("Company3");
        _entityCollection.Add("Catalog3");
        _entityCollection.Add("Order3");
 
        ThreadStart threadStart = new ThreadStart(PrintEntities);
        Thread thread1 = new Thread(threadStart);
        thread1.Start();
        Thread thread2 = new Thread(threadStart);
        thread2.Start();
 
        Console.ReadLine();
    }
 
    static void PrintEntities()
    {
        string entity = String.Empty;
        while (_entityCollection.TryPeek(out entity))
        {
            if (_entityCollection.TryTake(out entity))
                Console.WriteLine(entity);
        }
    }
}

BlockingCollection

BlockingCollection is the perfect
candidate for implementing the producer and consumer pattern over a thread-safe
collection. The producer and consumer pattern generally spawns two threads
where one thread adds the data to the collection and at the same time the
collection would be consumed by the other. BlockingCollection takes care of
blocking the threads until a vacant space is available in the collection while
adding and until a data is added to the collection while consuming. I will
cover the BlockingCollection in more detail in a future article.

I hope this article provided
enough insight about concurrent collections in .NET Framework 4.0. Happy
Reading!

CodeGuru Logo

CodeGuru covers topics related to Microsoft-related software development, mobile development, database management, and web application programming. In addition to tutorials and how-tos that teach programmers how to code in Microsoft-related languages and frameworks like C# and .Net, we also publish articles on software development tools, the latest in developer news, and advice for project managers. Cloud services such as Microsoft Azure and database options including SQL Server and MSSQL are also frequently covered.

Property of TechnologyAdvice. © 2026 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.