Other

Understanding Lazy<T> thread safety modes

Andrew Lock walks through the three LazyThreadSafetyMode values for Lazy<T> and shows how each interacts with exceptions thrown by the factory method. Because exception caching is tied to the thread-safety mode rather than being a separate switch, a Lazy<T> that fails once can stay permanently broken in two of the three modes.

Published
Reading time
10 min read
agent run #24
agent run #24
Go to original andrewlock.net

Report this story

Is something wrong with the summary, or do you own this content? Your message comes straight to my inbox.

Type of message

Key points

  • None gives no thread safety; concurrent access can throw InvalidOperationException
  • PublicationOnly lets threads race, publishes the first completed value and discards the rest
  • ExecutionAndPublication runs the factory once and blocks all other threads until it finishes
  • None and ExecutionAndPublication cache exceptions, so a single failure can leave the Lazy<T> permanently broken
  • PublicationOnly does not cache exceptions; once a value is published, callers just get that value
  • A proposal to separate exception caching via a cacheExceptions flag was approved, likely for .NET 12

Lazy<T>, available since .NET Framework 4.0, defers creation of an expensive object until the Value property is first read. The post compares the three LazyThreadSafetyMode values and shows they control two things at once: how concurrent access is coordinated and what happens when the factory method throws. With None there is no thread safety at all, so multi-threaded access tends to produce InvalidOperationException, and a nullable field with ??= often expresses the same intent more simply.

PublicationOnly lets every thread run the factory and race; the first thread to finish publishes its value and the losers' results are thrown away. That can beat locking when the factory is cheap, safe to repeat and contention is high. ExecutionAndPublication runs the factory exactly once and blocks the rest. The important difference: None and ExecutionAndPublication cache the exception and rethrow it to every later caller, while PublicationOnly does not.

Real-world use

  • Deferring creation of an expensive config object or HTTP client until first use
  • Guaranteeing a singleton service initializes once and understanding why retries keep throwing the same exception
  • Choosing PublicationOnly to avoid lock contention when the factory is cheap and safe to repeat
  • Using LazyInitializer.EnsureInitialized to avoid an extra Lazy<T> allocation on a hot path

Why it matters

A cached exception turns a transient initialization failure into a permanent one for the lifetime of the object, so picking a safety mode is a resilience decision as much as a performance one.

This summary was generated by the agent from the original post on Andrew Lock | .NET Escapades. The full text and all rights belong to its author and publisher. Go to original

Related stories

Feedback

Found a bug or have an idea? Your message lands straight in my inbox.

Type of message