简体   繁体   中英

Use of volatile in singleton double null check implementation in java

I want to know what is use of making Instance variable as volatile in double null check implementation of Singleton. Because as per my understanding synchronize block provide happens before implicitly. No two threads can access that synchronized block concurrently and while exiting from synchronized block, thread write all its local cached data to main memory. I search a lot but still i have doubts in this implementation. Please explain correct use.

private volatile Singleton INSTANCE; 
public Singleton get() { 
    if (INSTANCE == null) { 
        synchronized (this) { 
            if (INSTANCE == null) { 
                INSTANCE = new Singleton(); 
            } 
        } 
    } 
    return INSTANCE; 
}

In above double checking code. What may b the issue if i dont make my instance as volatile. Because when first thread enter in synchronize block, no other thread will get access to that block. And when first thread leaves that block. Object will be created and due to happens before property, latest value of instance will be written in main memory. So why volatile is important in this scenario?

Here's a link ( Is there any need to add volatile keyword to guarantee thread-safe singleton class in java? ) of similar question. But answers are not very clear. I don't think in above given scenario any kind of JVM optimization can cause breaking of happens before of synchronize block

Because as per my understanding synchronize block provide happens before implicitly. No two threads can access that synchronized block concurrently and while exiting from synchronized block

It is correct if you have a simple lazy singleton implementation. In that every access to the variable goes through syncronized block.

private Singleton INSTANCE;

public static synchronized Singleton getInstance() {
  if (INSTANCE == null) {
    INSTANCE = new Singleton();
  }
  return INSTANCE;
}

But once you have a safe double-check lazy implementation, not every code path goes through synchronized block. The second call to this method will read the variable from a local field without entering synchronized block and the INSTANCE has to be volatile.

private volatile Singleton INSTANCE;

public Singleton get() {
  if (INSTANCE == null) {
    synchronized (this) {
      if (INSTANCE == null) {
        INSTANCE = new Singleton();
      }
    }
  }
  return INSTANCE;
}

You can read more about safe publishing in this article .

volatile is important here because of the internals of the JVM on the bytecode level. The statement

INSTANCE = new Singleton()

is on bytecode level actually something like that:

1. INSTANCE = create Singleton object
2. call constructor of INSTANCE

if INSTANCE is volatile the JVM guarantees you that 1+2 are executed as an atomic operation from the point of view of other threads, eg by storing the instance on the stack before storing it in the field. If it is not volatile it might be that other threads can already see the reference to Singleton before the constructor has been called. Thus these threads might see an incomplete object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM