C#

ConcurrentDictionary in C# – Introduction, Examples

ConcurrentDictionary is one of five collection classes introduced in.NET 4.0. It exists in System.Collections.Concurrent namespace. ConcurrentDictionary is a thread-safe collection class to store key-value pairs. ConcurrentDictionary can be used with multiple threads concurrently. 

Without ConcurrentDictionary class, if we have to use Dictionary class with multiple threads, then we have to use locks to provides thread-safety which is always error-prone. ConcurrentDictionary provides you an easy option. It internally manages the locking gives you an easy interface to add/update items.

ConcurrentDictionary uses different methods to add, retrieve, update, and remove items.

Add items in ConcurrentDictionary

We can use TryAdd method to add a new key/value pair. Below is the example:

static void Main(string[] args)
{
    ConcurrentDictionary<string, string> dict = new ConcurrentDictionary<string, string>();
    dict.TryAdd("1", "First");
    dict.TryAdd("2", "Second");
}

TryAdd methods returns true if key/value pair is added, and returns false if key already exists in dictionary.

static void Main(string[] args)
{
    ConcurrentDictionary<string, string> dict = new ConcurrentDictionary<string, string>();
    bool firstItem = dict.TryAdd("1", "First");  //returns true
    bool secondItem = dict.TryAdd("2", "Second");  //returns  true

    bool thirdItem = dict.TryAdd("1", "Third"); //returns false;
}

In the above example, we try to add new item with the same key, TryAdd method returns false.

Retrieve Single Item using Key

To retrieve single item, ConcurrentDictionary provides TryGetValue method.

We have to provide Key in the TryGetValue method. It takes the out parameter to return the value of key. TryGetValue returns true if key exists, or returns false if key does not exists in dictionary.

static void Main(string[] args)
{
    ConcurrentDictionary<string, string> dict = new ConcurrentDictionary<string, string>();
    bool firstItem = dict.TryAdd("1", "First");
    bool secondItem = dict.TryAdd("2", "Second");

    string itemValue1;
    string itemValue2; 
    bool isItemExists1 = dict.TryGetValue("1", out itemValue1);  //returns true
    Console.WriteLine(itemValue1); //Print "First"

    bool isItemExists2 = dict.TryGetValue("3", out itemValue2);  //returns false
    Console.WriteLine(itemValue2); //Print blank
}

Retrieve all items in ConcurrentDictionary

As ConcurrentDictionary implements the IEnumerable interface, we can use foreach loop to enumerate all items in dictionary.

As with other dictionary class in .NET, It also does not returns all items in the order we have added in dictionary. We may get second item in first index, and first item in second index. Below is the example:

static void Main(string[] args)
{
    ConcurrentDictionary<string, string> dictionary = new ConcurrentDictionary<string, string>();
    dictionary.TryAdd("1", "First");
    dictionary.TryAdd("2", "Second");
    dictionary.TryAdd("3", "Third");
    dictionary.TryAdd("4", "Fourth");

    foreach(var item in dictionary)
    {
        Console.WriteLine(item.Key + "-" + item.Value);
    }
    //Returns 
    // 4- Fourth
    // 3 - Third
    // 2 - Second
    // 1 - First
}

Note: Enumeration is thread-safe in ConcurrentDictionary.

We have created two tasks. First task is adding new values and second task is enumerating all the items. We will not get any exception in below example.

static void Main(string[] args)
{
    ConcurrentDictionary<string, string> dictionary = new ConcurrentDictionary<string, string>();


    Task t1 = Task.Factory.StartNew(() =>
        {
            for (int i = 0; i < 100; ++i)
            {
                dictionary.TryAdd(i.ToString(), i.ToString());
                Thread.Sleep(100);
            }
        });

    Task t2 = Task.Factory.StartNew(() =>
        {
            Thread.Sleep(300);
            foreach (var item in dictionary)
            {
                Console.WriteLine(item.Key + "-" + item.Value);
                Thread.Sleep(150);
            }
        });

    try
    {
        Task.WaitAll(t1, t2);
    }
    catch (AggregateException ex) // No exception
    {
        Console.WriteLine(ex.Flatten().Message);  
    }

}

Update item

ConcurrentDictionary provides TryUpdate methods to update any key. TryUpdate takes three parameters. Three parameters are:

  1. Key – key to modify
  2. New Value – new value of the key
  3. Old Value – old value of the key

TryUpdate method update only when Key value matches with the old value, then it update the key with new value. It returns true if it successfully update the value else returns false. Below is the example:

static void Main(string[] args)
{
    ConcurrentDictionary<string, string> dictionary = new ConcurrentDictionary<string, string>();
    dictionary.TryAdd("1", "First");
    dictionary.TryAdd("2", "Second");
    dictionary.TryAdd("3", "Third");
    dictionary.TryAdd("4", "Fourth");

    string newValue;

    bool returnTrue = dictionary.TryUpdate("1", "New Value", "First"); //Returns true
    dictionary.TryGetValue("1", out newValue);
    Console.WriteLine(newValue); //Print "New Value"

    bool returnsFalse = dictionary.TryUpdate("2", "New Value 2", "No Value"); //Returns false
    dictionary.TryGetValue("2", out newValue);  //Returns "Second" Old value
    Console.WriteLine(newValue);    //Print "Second"
}

Remove item

For remove any item, ConcurrentDictionary provides TryRemove method. TryRemove returns true if it successfully removes the item else returns false. It also returns the removed item in the out parameter. Below is the example:

static void Main(string[] args)
{
    ConcurrentDictionary<string, string> dictionary = new ConcurrentDictionary<string, string>();
    dictionary.TryAdd("1", "First");
    dictionary.TryAdd("2", "Second");
    dictionary.TryAdd("3", "Third");
    dictionary.TryAdd("4", "Fourth");

    string removedItem;
    bool result = dictionary.TryRemove("2", out removedItem); //Returns true
    Console.WriteLine(removedItem); //Print "Second"
}

Remove all items in ConcurrentDictionary

For removing all items, we can use Clear method. It removes all the keys and its values from dictionary. Below is the example.

static void Main(string[] args)
{
    ConcurrentDictionary<string, string> dictionary = new ConcurrentDictionary<string, string>();
    dictionary.TryAdd("1", "First");
    dictionary.TryAdd("2", "Second");

    dictionary.Clear();

    foreach (var item in dictionary) //enumerate 0 times
    {
        Console.WriteLine(item.Key);
    }
}

Count all Items

ConcurrentDictionary provides Count method to returns the total number of items. Below is the example.

static void Main(string[] args)
{
    ConcurrentDictionary<string, string> dictionary = new ConcurrentDictionary<string, string>();
    dictionary.TryAdd("1", "First");
    dictionary.TryAdd("2", "Second");
    dictionary.TryAdd("3", "Third");
    dictionary.TryAdd("4", "Fourth");

    int totalItems = dictionary.Count(); // Returns 4

    int filterItems = dictionary.Count(w => w.Value.ToLower().Contains("t")); //Returns 3
}

ConcurrentDictionary also provides an overloaded method of Count() which takes the Predicate to filter the items.

Check Key exists

To check particular key exits in dictionary, we can use ContainsKey method. It returns true if key exists otherwise returns false.

static void Main(string[] args)
{
    ConcurrentDictionary<string, string> dictionary = new ConcurrentDictionary<string, string>();
    dictionary.TryAdd("1", "First");
    dictionary.TryAdd("2", "Second");
    dictionary.TryAdd("3", "Third");
    dictionary.TryAdd("4", "Fourth");

    bool firstItemFound = dictionary.ContainsKey("1"); //Returns true
    bool fifthItemFound = dictionary.ContainsKey("5"); //Returns false
}

Copy ConcurrentDictionary items to another Collection classes

For copy stored key/values pairs to another collection class, It provides different “To…” methods.

  1. ToArray
  2. ToDictionary
  3. ToList
  4. ToLookup

We can use above methods to copy over dictionary values into another collection classes. Below is the example.

static void Main(string[] args)
{
    ConcurrentDictionary<string, string> dictionary = new ConcurrentDictionary<string, string>();
    dictionary.TryAdd("1", "First");

    KeyValuePair<string, string>[] keyValues = dictionary.ToArray();

    Dictionary<string, string> dict = dictionary.ToDictionary(w => w.Key, m => m.Value);

    List<KeyValuePair<string, string>> lst = dict.ToList();

    ILookup<string, string> lookup = dict.ToLookup(w => w.Key, m => m.Value);
}

Final Words

ConcurrentDictionary is a thread-safe collection class to store key-value pairs. It internally uses locking to provide you with a thread-safe class. It provides different methods as compared to the dictionary class. We can use TryAdd, TryUpdate, TryRemove, and TryGetValue to do CRUD operations on ConcurrentDictionary.