What is the difference between Dictionary and ConcurrentDictionary?
Quick Answer
Dictionary<K,V> is not thread-safe — concurrent writes (or a write during a read) corrupt it or throw. ConcurrentDictionary<K,V> is thread-safe with fine-grained locking and atomic operations like GetOrAdd, AddOrUpdate, TryUpdate. Use it for shared caches; use a plain Dictionary for single-threaded or read-only-after-build data.
A plain Dictionary isn't thread-safe — if two threads write at once, or one writes while another reads, you can corrupt the internal state or get an exception. ConcurrentDictionary handles that with lock striping and gives you atomic helpers like GetOrAdd and AddOrUpdate. The subtlety with GetOrAdd is that the value factory can run twice under contention even though only one value wins, so I keep the factory cheap or wrap the value in a Lazy. For data that's built once and then only read, a normal dictionary is faster.
GetOrAdd(key, factory)is atomic for the dictionary, but the factory can run more than once under contention (only one result is kept) — make the factory cheap or idempotent, or useLazy<T>as the value.- Enumerating a
ConcurrentDictionarygives a moment-in-time snapshot and won't throw during concurrent writes. CountandToArraytake all internal locks — avoid in hot paths.- For read-heavy, build-once data, a plain
Dictionary(orFrozenDictionaryin .NET 8) is faster.