Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

volatile in double-checked locking in Java [duplicate]

As I understand, this is a correct implementation of the double-checked locking pattern in Java (since Java 5):

class Foo {
    private volatile Bar _barInstance;
    public Bar getBar() {
        if (_barInstance == null) {
            synchronized(this) { // or synchronized(someLock)
                if (_barInstance == null) {
                    Bar newInstance = new Bar();
                    // possible additional initialization
                    _barInstance = newInstance;
                }
            }
        }
        return _barInstance;
    }
}

I wonder if absence of volatile is a serious error or just a slight imperfection with possible performance drawback assuming _barInstance accessed only through getBar.

My idea is the following: synchronized introduces happens-before relation. The thread that initializes _barInstance writes its value to the main memory leaving the synchronized block. So there will be no double initialization of _barInstance even when it isn't volatile: other threads have null in theirs local copies of _barInstance (get true in the first check), but have to read the new value from the main memory in the second check after entering the synchronized block (get false and do no re-initialization). So the only problem is an excessive one-per-thread lock acquisition.

As I understand, it's correct in CLR and I believe it's also correct in JVM. Am I right?

Thank you.

like image 504
Ivan Yurchenko Avatar asked Mar 18 '23 07:03

Ivan Yurchenko


1 Answers

Not using volatile may result in errors in the following case:

  • Thread 1 enters getBar() and finds _barInstance to be null
  • Thread 1 attempts to create a Bar object and update the reference to _barInstance. Due to certain compiler optimisations, these operations may be done out of order.
  • Meanwhile, thread 2 enters getBar() and sees a non-null _barInstance but might see default values in member fields of the _barInstance object. It essentially sees a partially constructed object but the reference is not null.

The volatile modifier will prohibit a write or read of the variable _barInstance with respect to any previous read or write. Hence, it will make sure that thread 2 will not see a partially constructed object.

For more details: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

like image 50
Gaurav Avatar answered Mar 19 '23 21:03

Gaurav