public static void Main()
var lazy = new LazyWithRetry<int>(() =>
Print($"**Value factory invoked");
var value = Interlocked.Increment(ref counter);
if (value <= 2) throw new ApplicationException($"Oops! ({value})");
var workers = Enumerable.Range(1, 10).Select(n => new Thread(() =>
Print($"Worker #{n} before requesting value");
Print($"--Worker #{n} received value: {value}");
Print($"--Worker #{n} failed: {ex.Message}");
workers.ForEach(w => w.Start());
workers.ForEach(w => w.Join());
public class LazyWithRetry<T>
private volatile Lazy<T> _lazy;
public LazyWithRetry(Func<T> valueFactory)
ArgumentNullException.ThrowIfNull(valueFactory);
Func<T> valueFactoryWrapper = null;
valueFactoryWrapper = () =>
try { return valueFactory(); }
catch { _lazy = new Lazy<T>(valueFactoryWrapper); throw; }
_lazy = new Lazy<T>(valueFactoryWrapper);
public T Value => _lazy.Value;
public class AtomicLazy<T>
private readonly Func<T> _valueFactory;
private bool _initialized;
public AtomicLazy(Func<T> valueFactory)
_valueFactory = valueFactory;
public T Value => LazyInitializer
.EnsureInitialized(ref _value, ref _initialized, ref _lock, _valueFactory);
public class SimpleLazy<T>
private readonly object _locker = new object();
private readonly Func<T> _valueFactory;
private (T Value, bool HasValue) _cached;
public SimpleLazy(Func<T> valueFactory)
_valueFactory = valueFactory;
_cached = (_valueFactory(), true);
static void Print(object value)
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} {($"[{Thread.CurrentThread.ManagedThreadId}]"),4} > {value}");