using System.Collections.Concurrent;
using System.Threading.Tasks;
public static void Main()
private static readonly ConcurrentDictionary<int, CustomLazy<CacheableItem>>
cacheableItemCache = new ConcurrentDictionary<int, CustomLazy<CacheableItem>>();
private static CacheableItem RetrieveCacheableItem(int itemId)
Console.WriteLine("--RETRIEVE called\t ItemId [{0}] ThreadId [{1}]", itemId, Thread.CurrentThread.ManagedThreadId);
private static void GetCacheableItemGood(int itemId)
Console.WriteLine("GET good called\t ItemId [{0}] ThreadId [{1}]", itemId, Thread.CurrentThread.ManagedThreadId);
CacheableItem cacheableItem = cacheableItemCache
x => new CustomLazy<CacheableItem>(itemId,
() => RetrieveCacheableItem(itemId)
private static void GetCacheableItemBad(int itemId)
Console.WriteLine("GET bad called\t ItemId [{0}] ThreadId [{1}]", itemId, Thread.CurrentThread.ManagedThreadId);
CacheableItem cacheableItem = cacheableItemCache
new CustomLazy<CacheableItem>(itemId,
() => RetrieveCacheableItem(itemId)
public static void TestLazyEvaluation()
int[] itemIds = { 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5 };
ParallelOptions options = new ParallelOptions
MaxDegreeOfParallelism = 75
Parallel.ForEach(itemIds, options, itemId =>
GetCacheableItemGood(itemId);
GetCacheableItemGood(itemId);
GetCacheableItemGood(itemId);
GetCacheableItemGood(itemId);
GetCacheableItemGood(itemId);
Parallel.ForEach(itemIds, options, itemId =>
GetCacheableItemBad(itemId);
GetCacheableItemBad(itemId);
GetCacheableItemBad(itemId);
GetCacheableItemBad(itemId);
GetCacheableItemBad(itemId);
private class CustomLazy<T> : Lazy<T> where T : class
public CustomLazy(int itemId, Func<T> valueFactory)
Console.WriteLine("-Lazy Constructor called\t ItemId [{0}] ThreadId [{1}]", itemId, Thread.CurrentThread.ManagedThreadId);
private class CacheableItem
public int ItemId { get; set; }