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

5

46
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 ?

Excursive answered 24/7, 2012 at 21:40 Comment(1)
Related posts here and here about why double checking is even required in first place.Kohinoor
D
34

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;
    }
}
Desantis answered 24/7, 2012 at 21:44 Comment(3)
double checked locking can be necessary in certain situations where you have a singleton that can change during runtime, but may exist only once in your program. i.e. a login session, which you want to use to access a site, but you have to reconnect and get a new one once in a while. If the value doesn't change during runtime however, you should avoid itRachael
How will you pass arguments to the constructor in case of holder idiom?Suzette
Doesn't the synchronized block ensure that the non-cached values of the fields will be retrieved, meaning that the volatile part is not needed anymore ? Is this still required even today?Sideward
L
78

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.

Liturgical answered 24/7, 2012 at 22:5 Comment(12)
To be specific, the two reordered writes are: 1) A assigns memory address to uniqueInstance, and 2) XYZ gets something meaningful.Nygaard
@dasblinkenlight : you have said that "because the CPU has reordered writes....". Please explain what reordering writes mean?Dyewood
Just as thread A gets ready to release its lock Is it really matter?Flashlight
@dasblinkenlight What is the meaning of "prevents memory writes from being re-ordered"?Macronucleus
@NeelabhSingh It means, literally, what it says - if your code says it wants to write to location A before location B, having volatile ensures that A is actually written before B. Without volatile in place, CPU is free to write B before A, as long as it makes no detectable difference to the logic of your code.Liturgical
what if instance has two variables, XYZ is initialized but DEF not and XYZ is initialised and before DEF can start ,other thread comes and see non null and tries to access DFE,since earlier thread did not try to start DEF write,How would volatile help?Ilk
@Ilk the other thread cannot see the instance until the singleton pointer is stored.Liturgical
but once you create memory. instance= new instance, you got it initialised,now t1 does this and also does intance.XYZ=123, and the next statement is instance.DEF, bit before it does the DEF statment, it got preempted after it completed instance.XYZ, now CPU does not have any pending writes with it as thread did try to start instance.DEF, how what if thread 2 comes and read it?Ilk
@Ilk You do not assign ` instance= new Instance(), you assign a local tmp = new Instance(), then check again, and finally do instance = tmp`. See Mark's code in the accepted answer.Liturgical
ah got that. Too much complexity :(. Can we just have static variable as , private static final Foo INSTANCE = new Foo();, and then our getInstance can just return this instead of volatile and all threading and also it is thread safe,I saw some posts suggesting this way.Ilk
Won't if help, if manually call Thread.MemoryBarrier(); before assigning variable?Poulenc
Oh, it's Java, not c#. My badPoulenc
D
34

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;
    }
}
Desantis answered 24/7, 2012 at 21:44 Comment(3)
double checked locking can be necessary in certain situations where you have a singleton that can change during runtime, but may exist only once in your program. i.e. a login session, which you want to use to access a site, but you have to reconnect and get a new one once in a while. If the value doesn't change during runtime however, you should avoid itRachael
How will you pass arguments to the constructor in case of holder idiom?Suzette
Doesn't the synchronized block ensure that the non-cached values of the fields will be retrieved, meaning that the volatile part is not needed anymore ? Is this still required even today?Sideward
L
11

To avoid using double locking, or volatile I use the follow

enum Singleton {
     INSTANCE;
}

Creating the instance is simple, lazy loaded and thread safe.

Luting answered 25/7, 2012 at 7:16 Comment(0)
F
2

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

Felix answered 8/6, 2016 at 7:26 Comment(0)
A
-4

You can use the follow code:

private static Singleton uniqueInstance;

public static synchronized Singleton getInstance(){
    if(uniqueInstance == null){
        uniqueInstance = new Singleton();
    }
    return uniqueInstance
}
Algeciras answered 17/5, 2017 at 2:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.