Threading  

Why not use Dictionaries in Multi-Thread Apps

Working with collections in multi-threaded applications can be tricky. Most developers at first assume that Dictionaries are thread-safe.

If multiple threads read and write to a Dictionary at the same time, you risk corrupted state, and runtime exceptions.

Fortunately, .NET provides safer alternatives: ConcurrentDictionary and ImmutableDictionary.

Dictionary: Fast, but Unsafe

A Dictionary is optimized for single-threaded performance.

If multiple threads perform concurrent writes, it can throw exceptions such as:

var dict = new Dictionary<int, string>();

Parallel.For(0, 1000, i =>
{
    dict[i] = $"Value {i}";
});

This may result in:

  • Crashes (InvalidOperationException)

  • Wrong Count

ConcurrentDictionary: Thread-Safe, Mutable

The ConcurrentDictionary is designed for multi-threaded access.

var dict = new ConcurrentDictionary<int, string>();

Parallel.For(0, 1000, i =>
{
    dict[i] = $"Value {i}"; // Safe and efficient
});

Key points

  • Uses fine-grained locking.

  • Thread-safe for both reads and writes.

  • Still mutable: once a value is set, any thread can overwrite it.

How is it immutable if it is thread-safe?

  • It manages concurrent access to its internal data structure through intelligent locking and lock-free techniques, allowing multiple threads to safely add, remove, or update key-value pairs.

  • Instead of locking the entire dictionary for every write operation, ConcurrentDictionary divides its internal data structure into segments or partitions. Each segment has its own lock.

  • When a thread needs to modify an item, it only acquires the lock for the specific segment containing that item.

This allows other threads to concurrently modify items in different segments, improving concurrency.

ImmutableDictionary: Thread-Safe, Immutable

The ImmutableDictionary ensures safety through immutability.

using System.Collections.Immutable;

var dict = ImmutableDictionary<int, string>.Empty;

Parallel.For(0, 1000, i =>
{
    dict = dict.SetItem(i, $"Value {i}"); // Each call creates a new dictionary
});

Key points

  • Immutable by design: once you have a reference, it never changes.

  • Always thread-safe, no locks needed.

  • Writes are slower (creates a new copy), but reads are extremely fast and safe.

method

This is a benchmark result displaying the difference between using Dictionary, ConcurrentDictionary, and ImmutableDictionary in Multi-Thread apps.