问题
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 ?
回答1:
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;
}
}
回答2:
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.
回答3:
To avoid using double locking, or volatile I use the follow
enum Singleton {
INSTANCE;
}
Creating the instance is simple, lazy loaded and thread safe.
回答4:
Write to a volatile field will happen before any read operation. Below is an example code for better understanding:
private static volatile ResourceService resourceInstance;
//lazy Initialiaztion
public static ResourceService getInstance () {
if (resourceInstance == null) { // first check
synchronized(ResourceService.class) {
if (resourceInstance == null) { // double check
// creating instance of ResourceService for only one time
resourceInstance = new ResourceService ();
}
}
}
return resourceInstance;
}
This link can serve you better http://javarevisited.blogspot.com/2011/06/volatile-keyword-java-example-tutorial.html
回答5:
You can use the follow code:
private static Singleton uniqueInstance;
public static synchronized Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance
}
来源:https://stackoverflow.com/questions/11639746/what-is-the-point-of-making-the-singleton-instance-volatile-while-using-double-l