I keep on running across code that uses double-checked locking, and I'm still confused as to why it's used at all.
I initially didn't know that double-checked locking is broken, and when I learned it, it magnified this question for me: why do people use it in the first place? Isn't compare-and-swap better?
if (field == null)
Interlocked.CompareExchange(ref field, newValue, null);
return field;
(My question applies to both C# and Java, although the code above is for C#.)
Does double-checked locking have some sort of inherent advantage compared to atomic operations?
The double checked pattern is used to avoid obtaining the lock every time the code is executed. If the call are not happening together then the first condition will fail and the code execution will not execute the locking thus saving resources.
Double-Checked Locking is widely cited and used as an efficient method for implementing lazy initialization in a multithreaded environment. Unfortunately, it will not work reliably in a platform independent way when implemented in Java, without additional synchronization.
Double checked locking of Singleton is a way to make sure that only one instance of Singleton class is created through an application life cycle.
Ans. There is no mapping of single ton with number of processor of the system. So double check locking will not fail depending on number of processor.
Does double-checked locking have some sort of inherent advantage compared to atomic operations?
(This answer only covers C#; I have no idea what Java's memory model is like.)
The principle difference is the potential race. If you have:
if (f == null)
CompareExchange(ref f, FetchNewValue(), null)
then FetchNewValue() can be called arbitrarily many times on different threads. One of those threads wins the race. If FetchNewValue() is extremely expensive and you want to ensure that it is called only once, then:
if (f == null)
lock(whatever)
if (f == null)
f = FetchNewValue();
Guarantees that FetchNewValue is only called once.
If I personally want to do a low-lock lazy initialization then I do what you suggest: I use an interlocked operation and live with the rare race condition where two threads both run the initializer and only one wins. If that's not acceptable then I use locks.
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