using System.Collections.Concurrent;
using System.Threading.Tasks;
public class SimpleLazy<T> where T : class
private readonly Func<T> valueFactory;
private readonly object locker = new object();
public SimpleLazy(Func<T> valueFactory)
this.valueFactory = valueFactory;
return instance ?? (instance = valueFactory());
public class LightsaberProvider
private static int _firstTime = 1;
public LightsaberProvider()
Console.WriteLine("LightsaberProvider ctor");
public string GetFor(string jedi)
Console.WriteLine("LightsaberProvider.GetFor jedi: {0}", jedi);
if (jedi == "2" && 1 == Interlocked.Exchange(ref _firstTime, 0))
throw new Exception("Dark side happened...");
return string.Format("Lightsaver for: {0}", jedi);
public class LightsabersCache
private readonly LightsaberProvider _lightsaberProvider;
private readonly ConcurrentDictionary<string, SimpleLazy<string>> _producedLightsabers;
public LightsabersCache(LightsaberProvider lightsaberProvider)
_lightsaberProvider = lightsaberProvider;
_producedLightsabers = new ConcurrentDictionary<string, SimpleLazy<string>>();
public string GetLightsaber(string jedi)
SimpleLazy<string> result;
if (!_producedLightsabers.TryGetValue(jedi, out result))
result = _producedLightsabers.GetOrAdd(jedi, key => new SimpleLazy<string>(() =>
Console.WriteLine("Lazy Enter");
var light = _lightsaberProvider.GetFor(jedi);
Console.WriteLine("Lightsaber produced");
public static void Main(string[] args)
Console.WriteLine("Maximum 1 'Dark side happened...' strings on the console there should be. No more, no less.");
Console.WriteLine("Maximum 5 lightsabers produced should be. No more, no less.");
private static void Test()
var cache = new LightsabersCache(new LightsaberProvider());
for (int i = 0; i < 10; i++)
var result = cache.GetLightsaber((t % 5).ToString());
Console.WriteLine(e.Message);