0

Below is the code for singleton pattern in java that can be found across internet. My question is what is the requirement to mark instance variable as volatile because we are using synchronization in getInstance() method and this should be enough to provide visibility grantee?

public class MySingleton {
    
    private volatile static MySingleton INSTANCE;
    
    private MySingleton() {
        super();
    }
    
    public static MySingleton getInstance() {
        if(INSTANCE == null) {
            synchronized (MySingleton.class) {
                if(INSTANCE == null)
                    INSTANCE = new MySingleton();
            }
        }
        return INSTANCE;
    }

}
Delphi
  • 71
  • 1
  • 8
  • that is an optimization; without it everyone will potentially enter the synchronized block, thus contention. – Eugene Aug 03 '21 at 18:21
  • Without volatile, you have the same problems as in http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html – fgb Aug 03 '21 at 19:06

1 Answers1

0

On INSTANCE null, several threads may be stalled on the synchronized. The first in the synchronized block will create the INSTANCE. And now volatile ensures that the other threads entering will have the updated value of INSTANCE, and not a stale null, repeating the creation.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • how can it repeat the creation if the read here `if(INSTANCE == null)` (second one) happens under the `synchronized (MySingleton.class)`, which means the write `INSTANCE = new MySingleton();` which happens under the same lock - will be visible. – Eugene Aug 03 '21 at 18:45
  • `volatile` is an optimization, so that the read `if(INSTANCE == null)` that is outside of the protected region is guaranteed to be seen, outside the synchronized block. – Eugene Aug 03 '21 at 18:48
  • @Eugene there seems to be a serious hole in my java education. I'll have to study. You are saying that as soon the first thread entering created the instances and leaves the block, all other threads will have an updated value of INSTANCE? – Joop Eggen Aug 03 '21 at 20:22
  • all other threads are parked at the synchronization lock, as long as one active thread does that write : `INSTANCE = new MySingleton();`. As soon as this thread exists the synchronized block _and_ other thread(s) enter this _same_ synchronized block (reads and writes are guaranteed only for the same lock), they will obviously see that `if(INSTANCE == null)` is `false`. Again, the crucial part here is that the read and write MUST happen for the same lock. The `volatile` introduction exists so that a write is visible without synchronization; so that reading it _outside_ a sync block... – Eugene Aug 03 '21 at 20:27
  • would still give the needed guarantees. you can have a "single check locking" and drop that first read (`if(INSTANCE == null) {`) in the "double check locking" (and implicitly drop `volatile`). This is how singleton pattern was done in the very beginning. Reasoning why DCL is broken without `volatile` is [complicated](https://stackoverflow.com/questions/59208041/do-we-need-volatile-when-implementing-singleton-using-double-check-locking/61166685#61166685). I have somehow an understanding of it. And its simplified, reality is much more complicated. – Eugene Aug 03 '21 at 20:31
  • @Eugene I understood DCL being broken; but I admit, I will do a refresher soon. – Joop Eggen Aug 03 '21 at 21:10