Java Threads: Should all shared variables be Volatile ?

This question already has an answer here:

  • Java volatile modifier and synchronized blocks

    3 answers

I am trying to understand how multithreading works in Java. I understand the difference between Volatile and Synchronization.

Volatile is about visibility and doesn’t guarantee synchronization. When we are working with multithreading environments, each thread creates its own copy on a local cache of the variable they are dealing with. When this value is being updated, the update happens first in the local cache copy, and not in the real variable. Therefore, other threads are agnostic about the values that other threads are changing. And this is where volatile comes into picture. Volatile fields are immediately written through to main memory, and reads occur from main memory.

Snippet from Thinking In Java –

Synchronization also causes flushing to main memory, so if a field is
completely guarded by synchronized methods or blocks, it is not
necessary to make it volatile.

It’s typically only safe to use volatile instead of synchronized if
the class has only one mutable field. Again, your first choice should
be to use the synchronized keyword—that’s the safest approach, and
trying to do anything else is risky.

But my question is, if in a synchronized block, a non volatile shared variable is being modified, will the other threads see the updated data ? (Since the variable in question is non volatile, other threads should read stale data from cache instead of main main memory)

If the answer to the above question is NO, then can I conclude that everytime I use synchronization, I should ensure that shared variables must be marked volatile ?

And if the answer is YES, then does that mean that I can always use synchronization instead of marking shared variables are volatile ?

p.s: Before asking this question, I have read through lot of answers on StackOverflow and on other sites, but I couldn’t find the answer to my question.

To simplify a little:

  • volatile only provides visibility: when you read a volatile variable you get two guarantees: (1) you see the latest write to the variable, even if it was performed in another thread and (2) all the writes before that volatile write are also visible.
  • synchronized gives you visibility AND atomicity – thread observing the actions performed in a synchronized block from a synchronized block using the same monitor will either see all of them or none of them.

So to answer your question, no, if a variable is written to within a synchronized block, you don’t need to mark it volatile, provided that you always read that variable from a synchronized block using the same monitor.


Here are a few examples with volatile:

static class TestVolatile {
  private int i = 0;
  private volatile int v = 0;

  void write() {
    i = 5;
    v = 7;
  }

  void read() {
    //assuming write was called beforehand
    print(i); //could be 0 or 5
    print(v); //must be 7
    print(i); //must be 5
  }

  void increment() {
    i = i + 1; //if two threads call the method concurrently
               //i could be incremented by 1 only, not 2: no atomicity
  }
}

And a few examples with synchronized:

static class TestSynchronized {
  private int i = 0;
  private int j = 0;

  void write() {
    synchronized(this) {
      i = 5;
      j = 7;
    }
  }

  void read_OK() {
    synchronized(this) {
      //assuming write was called beforehand
      print(i); //must be 5
      print(j); //must be 7
      print(i); //must be 5
    }
  }

  void read_NOT_OK() {
    synchronized(new Object()) { //not the same monitor
      //assuming write was called beforehand
      print(i); //can be 0 or 5
      print(j); //can be 0 or 7
    }        
  }

  void increment() {
    synchronized(this) {
      i = i + 1; //atomicity guarantees that if two threads call the method
                 //concurrently, i will be incremented twice
    }
  }
}

If that variable is protected by the same monitor lock every time it’s accessed then there is no need to make it volatile.

Synchronized blocks do two things: single thread access to the regions protected by a lock and visibility effects. The visibility effects mean that any changes made to that variable while being protected by that lock will be visible for any other thread which enters a region which uses it (the lock).

The JLS defines a relation called “happens-before” on instructions in a program. A short version can be seen in the documentation of java.util.concurrent.

A write operation to a variable is seen by a read operation of the same variable, if the write “happens-before” the read.

Now, if both threads access that variable only inside a synchronization block, then the exit from the synchronization block guarantees that what happened in it “happens-before” anything that happens after the next lock of the same synchronization monitor.

So if thread A writes to variable x inside a synchronized block, and thread B reads from that x inside a synchronized block on the same monitor, then x doesn’t need to be volatile – the write “happened before” the read and its result will be visible to thread B.

But if thread B reads the variable without synchronization, then even if thread A did it inside synchronization, there is no guarantee that the write “happens before”, and the variable is unsafe – unless it’s volatile.

So if you make sure all access – both read and write – is within synchronization blocks on the same monitor, then you can rely on the “happens before” relation to make your write visible.