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