
ConcurrentDictionary handles multiple threads. This type from the System.Collections.Concurrent namespace allows multiple threads to access a Dictionary instance. With ConcurrentDictionary, you get a hash-based lookup algorithm that is safe to use on multiple threads.
Tip: The ConcurrentDictionary type resides in System.Collections.Concurrent. It was introduced in .NET 4.0. It makes adding, removing and updating values in a lookup table on multiple threads easier.

These two programs compare the ConcurrentDictionary and the Dictionary type when adding keys and values to a collection. With ConcurrentDictionary, we use the TryAdd method: this will do nothing if the key is already found. It returns true if something was added. In the Dictionary program, we use the Add method. The Dictionary program will fail because you cannot Add an element that was already present.
Program that uses ConcurrentDictionary [C#]
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading;
class Program
{
static ConcurrentDictionary<string, int> _concurrent =
new ConcurrentDictionary<string, int>();
static void Main()
{
Thread thread1 = new Thread(new ThreadStart(A));
Thread thread2 = new Thread(new ThreadStart(A));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine("Average: {0}", _concurrent.Values.Average());
}
static void A()
{
for (int i = 0; i < 1000; i++)
{
_concurrent.TryAdd(i.ToString(), i);
}
}
}
Program that uses Dictionary [C#]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
class Program
{
static Dictionary<string, int> _dictionary = new Dictionary<string, int>();
static void Main()
{
Thread thread1 = new Thread(new ThreadStart(A));
Thread thread2 = new Thread(new ThreadStart(A));
thread1.Start();
thread2.Start();
thread1.Join();
thread2.Join();
Console.WriteLine("Average: {0}", _dictionary.Values.Average());
}
static void A()
{
for (int i = 0; i < 1000; i++)
{
_dictionary.Add(i.ToString(), i);
}
}
}One interesting feature of the ConcurrentDictionary is its focus on Try methods. These methods attempt to perform an action upon the contents of the collection, but return false if they cannot do it. The reason they cannot do something is usually because the given key is invalid. It may have been changed on another thread.
TryAdd
Shown in above example. This method is the same as the Add method on Dictionary
except it doesn't throw an exception if the key is already present.
TryGetValue
This is the same as the TryGetValue method on the Dictionary type from System.Collections.Generic.
TryRemove
This is somewhat different from the Remove method on the Dictionary.
It has a second, out parameter that returns the value that was removed.
TryUpdate
This can be used to update a key with the value you provide to a new value.
See the below example.
Let's look at an example of the TryUpdate method on the ConcurrentDictionary. In this example, the first call to TryUpdate doesn't do anything, because the value of "cat" is not equal to 4. The second call, though, does change the value from 1 to 100 because its value was set to 1.
Program that tests TryUpdate [C#]
using System;
using System.Collections.Concurrent;
class Program
{
static void Main()
{
// New instance.
var con = new ConcurrentDictionary<string, int>();
con.TryAdd("cat", 1);
con.TryAdd("dog", 2);
// Try to update if value if 4 (this fails).
con.TryUpdate("cat", 200, 4);
// Try to update if value is 1 (this works).
con.TryUpdate("cat", 100, 1);
// Write new value.
Console.WriteLine(con["cat"]);
}
}
Output
100Next, let's look at the "Or" methods on the ConcurrentDictionary: the AddOrUpdate and GetOrAdd methods. Conceptually, the AddOrUpdate method will always result in a value change in the collection. The GetOrAdd method, on the other hand, is the same as AddOrUpdate except it will not change the existing value: it will only return it.
Program that uses AddOrUpdate and GetOrAdd [C#]
using System;
using System.Collections.Concurrent;
class Program
{
static void Main()
{
// New instance.
var con = new ConcurrentDictionary<string, int>();
con.TryAdd("cat", 1);
con.TryAdd("dog", 2);
// Add dog with value of 5 if it does NOT exist.
// ... Otherwise, add one to its value.
con.AddOrUpdate("dog", 5, (k, v) => v + 1);
// Display dog value.
Console.WriteLine(con["dog"]);
// Get mouse or add it with value of 4.
int mouse = con.GetOrAdd("mouse", 4);
Console.WriteLine(mouse);
// Get mouse or add it with value of 660.
mouse = con.GetOrAdd("mouse", 660);
Console.WriteLine(mouse);
}
}
Output
3
4
4
Why these methods? The point of these methods, as with all the methods on the ConcurrentDictionary, is to resolve problems with the nature of time in concurrent systems. With multiple threads, you cannot predict what elements will be found in the collection at any point of execution. These fail-safe methods, then, are used to ensure the collection will not become corrupted or invalid even if you cannot predict what elements may be present in it.

The ToArray method on the ConcurrentDictionary type yields an array of KeyValuePair structs. For more information on KeyValuePair, please check out the specific article on this website.
KeyValuePair HintsThe ConcurrentDictionary collection introduces a new property, the IsEmpty property. Conceptually, this property is equivalent to the expression Count == 0. The collection can never contain a negative number of elements, and is only empty when there are zero elements.
There are more methods on the ConcurrentDictionary, but these have the same behavior as the methods found on the Dictionary. These members include Clear, ContainsKey, Count, GetEnumerator, Keys, and Values.
ContainsKey Method Dictionary Examples Dictionary GetEnumeratorWith these examples, we looked at the ConcurrentDictionary type and its intended usage. By facilitating error-free code in programs that use multiple threads, the ConcurrentDictionary can enhance lookup performance in complex, time-critical software.
Collections