How to Use ConcurrentDictionary in C# for Thread-Safe Collections
Use
ConcurrentDictionary<TKey, TValue> in C# to store key-value pairs safely across multiple threads without locks. It provides thread-safe methods like TryAdd, TryGetValue, and AddOrUpdate to manage data concurrently.Syntax
The ConcurrentDictionary<TKey, TValue> class is a thread-safe collection for storing key-value pairs. It supports concurrent read and write operations without needing explicit locks.
TKey: Type of the keys.TValue: Type of the values.- Common methods include
TryAdd(key, value),TryGetValue(key, out value),AddOrUpdate(key, addValueFactory, updateValueFactory), andTryRemove(key, out value).
csharp
ConcurrentDictionary<TKey, TValue> dictionary = new ConcurrentDictionary<TKey, TValue>();Example
This example shows how to create a ConcurrentDictionary, add items safely, update values, and retrieve them in a thread-safe way.
csharp
using System; using System.Collections.Concurrent; class Program { static void Main() { var dictionary = new ConcurrentDictionary<string, int>(); // Add a key-value pair bool added = dictionary.TryAdd("apple", 3); Console.WriteLine($"Added apple: {added}"); // Try to add the same key again added = dictionary.TryAdd("apple", 5); Console.WriteLine($"Added apple again: {added}"); // Update or add a key int newValue = dictionary.AddOrUpdate("apple", 1, (key, oldValue) => oldValue + 2); Console.WriteLine($"Updated apple value: {newValue}"); // Retrieve a value if (dictionary.TryGetValue("apple", out int value)) { Console.WriteLine($"Value for apple: {value}"); } // Remove a key bool removed = dictionary.TryRemove("apple", out int removedValue); Console.WriteLine($"Removed apple: {removed}, value was: {removedValue}"); } }
Output
Added apple: True
Added apple again: False
Updated apple value: 5
Value for apple: 5
Removed apple: True, value was: 5
Common Pitfalls
Common mistakes when using ConcurrentDictionary include:
- Assuming
TryAddalways adds the item; it returnsfalseif the key exists. - Using indexer
[key]to add or update without thread-safe guarantees for complex updates. - Not using
AddOrUpdateorGetOrAddfor atomic operations, which can cause race conditions.
Always use the provided thread-safe methods to avoid data corruption.
csharp
var dict = new ConcurrentDictionary<string, int>(); // Wrong: This is not atomic and can cause race conditions if (!dict.ContainsKey("key")) { dict["key"] = 1; // Another thread might add "key" here } // Right: Use GetOrAdd for atomic add or get int value = dict.GetOrAdd("key", 1);
Quick Reference
| Method | Description |
|---|---|
| TryAdd(key, value) | Adds a key-value pair if the key does not exist. |
| TryGetValue(key, out value) | Gets the value for a key if it exists. |
| AddOrUpdate(key, addValueFactory, updateValueFactory) | Adds or updates a key with a value atomically. |
| GetOrAdd(key, valueFactory) | Gets the value if key exists or adds it atomically. |
| TryRemove(key, out value) | Removes a key and returns its value if it exists. |
Key Takeaways
Use ConcurrentDictionary for thread-safe key-value storage without manual locks.
Prefer AddOrUpdate and GetOrAdd methods for atomic operations to avoid race conditions.
TryAdd returns false if the key already exists; it does not overwrite.
Avoid checking ContainsKey before adding; use thread-safe methods instead.
ConcurrentDictionary is ideal for multi-threaded environments where data safety is critical.