53

I saw some examples in java where they do synchronization on a block of code to change some variable while that variable was declared volatile originally .. I saw that in an example of singleton class where they declared the unique instance as volatile and they sychronized the block that initializes that instance ... My question is why we declare it volatile while we synch on it, why we need to do both?? isn't one of them is sufficient for the other ??

public class SomeClass {
    volatile static Object uniqueInstance = null;

    public static Object getInstance() {
        if (uniqueInstance == null) {
            synchronized (someClass.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new SomeClass();
                }
            }
        }
        return uniqueInstance;
    }
}

thanks in advance.

Nico Van Belle
  • 4,911
  • 4
  • 32
  • 49
Dorgham
  • 962
  • 1
  • 9
  • 17

5 Answers5

25

Synchronization by itself would be enough in this case if the first check was within synchronized block (but it's not and one thread might not see changes performed by another if the variable were not volatile). Volatile alone would not be enough because you need to perform more than one operation atomically. But beware! What you have here is so-called double-checked locking - a common idiom, which unfortunately does not work reliably. I think this has changed since Java 1.6, but still this kind of code may be risky.

EDIT: when the variable is volatile, this code works correctly since JDK 5 (not 6 as I wrote earlier), but it will not work as expected under JDK 1.4 or earlier.

Michał Kosmulski
  • 9,855
  • 1
  • 32
  • 51
  • 3
    you say that Synchronization would be enough if the first check was within synchronized block .... but I make the same check again after entering the synch block, so for sure the next thread will see the updated value of the variable. – Dorgham Mar 12 '12 at 11:21
  • Each thread may see a different snapshot, so the fact that one thread reads a variable inside a synchronized block does not mean that another thread which reads the variable without synchronization will see the same state. State will be consistent between threads only if they all use proper synchronization. As I mentioned, `volatile` takes care of that in your case from Java 5 upwards (i.e. `volatile` and `synchronized` not only cause a memory barrier each, but they also use the same barrier). – Michał Kosmulski Mar 12 '12 at 12:23
  • 6
    Just as a heads-up to future readers: the article linked above is way out of date and as the edit states, the technique works fine on JDK 5 which was released almost 10 years ago. – Steve Pomeroy Oct 08 '13 at 14:45
  • 3
    @MohammadDorgham @MichałKosmulski The second null check would always see the updated value. So does that mean the `volatile` is used only to fail the first null check for efficiency? (without `volatile` it would be slow but still correct?) – Weishi Z Jun 29 '16 at 23:51
  • 3
    From Oracle documentation "when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads" https://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html. I think it will be the case for synchronized block as well. If true then the blocked thread should see the updated value of "uniqueInstance". – user3386493 Feb 21 '17 at 18:06
  • 1
    @WeishiZeng Yes, it's just an optimization – Michał Kosmulski Feb 22 '17 at 07:53
  • If I understand correctly, since Java 5, declaring uniqueInstance volatile is merely a performance improvement. Even if I don't declare it volatile, the code is still correct, right? – Marko Cain Nov 19 '19 at 01:50
  • @MarkoCain No, you actually need the volatile. Without it, the first null check (the one outside synchronized block) is not synchronized and may give wrong results – Michał Kosmulski Nov 19 '19 at 08:40
  • @MichałKosmulski actually from a logical point of view, we do not need to declare it volatile, because the first null check might not be updated then, but it will return correctly at the second null check within the synchronized block (inside synchronized we have the up-to-date value). However, we need the volatile because it seems Java allows the publication of partially initialized objects, when volatile is not used, which means that a second thread could end up using an object which is not completely initialized. Volatile ensures that the reference points to a fully initialized object. – maxeh Jan 07 '22 at 16:01
  • Besides volatile, it seems there are also other ways to ensure a variable is correctly published and not partly initialized, e.g. by using a final variable. More details can be found here: https://wiki.sei.cmu.edu/confluence/display/java/TSM03-J.+Do+not+publish+partially+initialized+objects – maxeh Jan 07 '22 at 16:07
  • Correct @maxeh Everything within "syncronized" is guaranteed to be visible for other threads when the lock is released at the end. But while inside, instructions may be reordered. Therefore, because the 2nd thread checks `uniqueInstance` before entering "syncronized", it may see uncompleted object (object created and variable assigned, but constructor still in progress). – Artem Novikov Oct 09 '22 at 22:59
7

This uses the double checked locking, note that the if(uniqueInstance == null) is not within the synchronized part.

If uniqueInstance is not volatile, it might be "initialized" with a partially constructed object where parts of it isn't visible to other than the thread executing in the synchronized block. volatile makes this an all or nothing operation in this case.

If you didn't have the synchronized block, you could end up with 2 threads getting to this point at the same time.

if(uniqueInstance == null) {
      uniqueInstance = new someClass(); <---- here

And you construct 2 SomeClass objects, which defeats the purpose.

Strictly speaking, you don't need volatile , the method could have been

public static someClass getInstance() {
    synchronized(FullDictionary.class) {
         if(uniqueInstance == null) {
             uniqueInstance = new someClass();
          }
         return uniqueInstance;
    }
}

But that incurs the synchronization and serialization of every thread that performs getInstance().

nos
  • 223,662
  • 58
  • 417
  • 506
  • I did the synchronization after the if statement to reduce the cost of synchronization, so my question is why I need to make it volatile while I double check after entering the synch block? I mean synch will update all shared variables immediately, so the next thread will see the updated value of uniqueInstance – Dorgham Mar 12 '12 at 11:48
  • 1
    @user1262445 As I said, without volatile a thread can see the object as partially constructed. So it will never enter the synchronized block, but return an partially constructed object if uniqueInstance is not volatile. I.e. you have 1 thread not entering the synch block and it might return garbage as another thread is right in the middle of the synchornized block. – nos Mar 12 '12 at 11:53
  • My question is without `volititle`, indeed the first `if(uniqueInstance == null) {` may be pass even though it is initialized , but after it enter the synchronized block, the miss judgement will be fixed since it has been synchronized so `if(uniqueInstance == null) ` will be false and no new instance will be created, isn't it? So even without valitle , the code will still work as expected(only one same instance created and return ). But indeed has poorer performance? Am I right? – JaskeyLam May 17 '16 at 05:04
  • 1
    @nos I'm having the same doubt as @Jaskey. " New object is assigned to the variable only when the constructor return. And the default value for `uniqueInstance` is `null`. So inside `synchronized` block, how could it be a partially initialized object getting assigned to `uniqueInstance` ? – Weishi Z Jun 30 '16 at 05:42
  • @WeishiZeng What makes it not ? The compiler and runtime might 1. allocate the memory for your object, 2. assign that memory to uniqueInstance. 3. Run the constructor. Now, inbetween step 2 and 3, another thread could execute `if(uniqueInstance == null) {` which would be false, but `uniqueInstance` isn't finished being constructed, since step 3 isn't yet finished. There are other cases you can substitute for step 2 and 3 as well, dealing with memory visibility within the JVM. – nos Jun 30 '16 at 06:12
  • 1
    @nos thanks for the reply!! Yes this is getting close to my question. For the order of step #2 and #3, do you know where is it documented? `uniqueInstance = new someClass();` It seems to me that the object is assigned to the `uniqueInstance` only when the constructor return. (As my understanding of this SO http://stackoverflow.com/questions/7187842/will-long-running-constructors-create-half-initialized-objects) – Weishi Z Jun 30 '16 at 06:17
  • @WeishiZeng It isn't documented explicitly, it's among many things, a consequence of what is not documented, thus leaving opportunities for an implementation to do optimization - but you can start by reading about the Java memory model in JSR-133. The question you link to is correct when you only consider 1 thread, that thread will naturally see the variable beeing assigned to after the constructor is run. But that might not be what another thread sees, if it had access to the same variable, without any locking. – nos Jun 30 '16 at 06:36
  • @nos I've read thru the memory model at https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf. But couldn't find direct answer. Could you kindly take a look at this question? (http://stackoverflow.com/questions/7187842/will-long-running-constructors-create-half-initialized-objects) All the answers basically states: "the object is assigned to the variable only when the constructor return". Which means step#3 is before #2. Are they all wrong?? – Weishi Z Jun 30 '16 at 06:45
  • @WeishiZeng It is a consequence of what is stated in chapter 17.4. The question you link to does not mention multi threading, see what I wrote about that in the previous comment. – nos Jun 30 '16 at 06:57
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/116045/discussion-between-weishi-zeng-and-nos). – Weishi Z Jun 30 '16 at 07:01
6

This post explains the idea behind volatile.

It is also addressed in the seminal work, Java Concurrency in Practice.

The main idea is that concurrency not only involves protection of shared state but also the visibility of that state between threads: this is where volatile comes in. (This larger contract is defined by the Java Memory Model.)

Michael Easter
  • 23,733
  • 7
  • 76
  • 107
0

You can do synchronization without using synchronized block. It's not a necessary to use volatile variable in it... volatile updates the one variable from main memory..and synchronized Update all shared variables that have been accessed from main memory.. So you can use it according to your requirement..

-2

My two cents here

Frist a quick explanation of the intuition of this code

if(uniqueInstance == null) {
        synchronized(someClass.class) {
            if(uniqueInstance == null) {
                uniqueInstance = new someClass();
            }
        }
    }

The reason it checks uniqueInstance == null twice is to reduce the overhead of calling the synchronized block which is relatively slower. So called double-checked locking.

Second, the reason it uses synchronized is easy to understand, it make the two operations inside the synchronized block atomic.

Last the volatile modifier makes sure all threads see the same copy so the very first check outside of the synchronized block will see the value of uniqueInstance in a way which is "synchronized" with the synchronized block. Without the volatile modifier one thread can assign a value to uniqueInstance but the other thread may not see it by the first check. (Although the second check will see it)

zfy
  • 4,497
  • 1
  • 11
  • 7