Let's say we have:
var dictionary = new ConcurrentDictionary<string, Lazy<Heavy>>();
Instantiating Heavy is very resource-consuming. Let's consider this code:
return dictionary.GetOrAdd("key", key =>
{
return new Lazy<Heavy>(() =>
{
return Instantiate();
});
}).Value;
The method Instantiate() of course returns an instance of type Heavy.
For a given key, is it 100% guaranteed that the method Instantiate() will be invoked at most once?
Some people claim that having multiple threads, we can only create multiple instances of Lazy<Heavy>, which is very cheap. The actual method Instantiate() will be invoked at most once.
I personally have an impression that this is false. What is the truth?
Instantiate will indeed will execute only once. Documentation of GetOrAdd says:
If you call GetOrAdd simultaneously on different threads, addValueFactory may be called multiple times, but its key/value pair might not be added to the dictionary for every call.
What that means is: even if addValueFactory is run multiple times - only one of returned values will actually be added to dictionary and returned from GetOrAdd call. So if two threads call GetOrAdd at the same time with the same key - 2 Lazy<Heavy> instances are created, but only 1 instance is added to dictionary and returned from both GetOrAdd calls, the other is discarded (so, even if factory has been run - it does not mean value provided by this factory is what is finally returned from GetOrAdd). Because you call .Value on the result of GetOrAdd - you call that always on single instance of Lazy<Heavy> and so Instantiate always runs at most once.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With