Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the point of making the singleton instance volatile while using double lock? [duplicate]

private volatile static Singleton uniqueInstance 

In a singleton when using double lock method for synchronization why is the single instance declared as volatile ? Can I achieve the same functionality without declaring it as volatile ?

like image 433
Phoenix Avatar asked Jul 24 '12 21:07

Phoenix


People also ask

What is the benefit of using a double checking lock mechanism in singleton?

This double check lock is only necessary if you are worried about many threads calling the singleton simultaneously, or the cost of obtaining a lock in general. Its purpose is to prevent unnecessary synchronization, thereby keeping your code fast in a multi-threaded environment.

Why volatile with double checked locking?

Since it requires the volatile keyword to work properly, it's not compatible with Java 1.4 and lower versions. The problem is that an out-of-order write may allow the instance reference to be returned before the singleton constructor is executed. Performance issue because of decline cache for volatile variable.

What is double locking in singleton?

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.

How do you make a singleton class thread safe volatile?

Thread Safe Singleton in JavaCreate the private constructor to avoid any new object creation with new operator. Declare a private static instance of the same class. Provide a public static method that will return the singleton class instance variable.


2 Answers

The volatile prevents memory writes from being re-ordered, making it impossible for other threads to read uninitialized fields of your singleton through the singleton's pointer.

Consider this situation: thread A discovers that uniqueInstance == null, locks, confirms that it's still null, and calls singleton's constructor. The constructor makes a write into member XYZ inside Singleton, and returns. Thread A now writes the reference to the newly created singleton into uniqueInstance, and gets ready to release its lock.

Just as thread A gets ready to release its lock, thread B comes along, and discovers that uniqueInstance is not null. Thread B accesses uniqueInstance.XYZ thinking that it has been initialized, but because the CPU has reordered writes, the data that thread A has written into XYZ has not been made visible to thread B. Therefore, thread B sees an incorrect value inside XYZ, which is wrong.

When you mark uniqueInstance volatile, a memory barrier is inserted. All writes initiated prior to that of uniqueInstance will be completed before the uniqueInstance is modified, preventing the reordering situation described above.

like image 200
Sergey Kalinichenko Avatar answered Oct 03 '22 03:10

Sergey Kalinichenko


Without volatile the code doesn't work correctly with multiple threads.

From Wikipedia's Double-checked locking:

As of J2SE 5.0, this problem has been fixed. The volatile keyword now ensures that multiple threads handle the singleton instance correctly. This new idiom is described in The "Double-Checked Locking is Broken" Declaration:

// Works with acquire/release semantics for volatile // Broken under Java 1.4 and earlier semantics for volatile class Foo {     private volatile Helper helper = null;     public Helper getHelper() {         Helper result = helper;         if (result == null) {             synchronized(this) {                 result = helper;                 if (result == null) {                     helper = result = new Helper();                 }             }         }         return result;     }      // other functions and members... } 

In general you should avoid double-check locking if possible, as it is difficult to get right and if you get it wrong it can be difficult to find the error. Try this simpler approach instead:

If the helper object is static (one per class loader), an alternative is the initialization on demand holder idiom

// Correct lazy initialization in Java  @ThreadSafe class Foo {     private static class HelperHolder {        public static Helper helper = new Helper();     }      public static Helper getHelper() {         return HelperHolder.helper;     } } 
like image 25
Mark Byers Avatar answered Oct 03 '22 04:10

Mark Byers