2

I was reading about synchronized and volatile in java. Each new article makes me confused. One article said "Java’s synchronized keyword guarantees both mutual exclusion and visibility". I am not sure about the visibility part. Isn't visibility problems solved by volatile in java. Lets consider this small program.

class SharedObj
  {
    volatile int sharedVar = 6;

   public int synchronized getVar(){
          return sharedVar; 
         }

   public synchronized setVar(int i){
          return sharedVar=i; 
        }

}

Lets say this is run by 10 threads , 5 for read and 5 by write on same SharedObj object. Here we need both synchronized as well as volatile?

volatile : As every thread will cache the sharedVar in to local cache.

synchronized : one thread at a time.

  • 1
    If the method is `synchronized` and the method contains 20000 variables, would you expect all of them to be marked `volatile` as well? – Thomas Weller Sep 23 '18 at 11:57
  • @Thomas .. my confusion is regarding the instance variable (sharedVar in example) not local variable. – Java Beginner Sep 23 '18 at 12:10
  • As I understood from the threads posted in the comments, `volative` can be omitted for `sharedVar` – Maxim Sep 23 '18 at 12:57
  • 2
    @Maxim Yes, by synchronizing the `getter` and `setter` and making `sharedVar` private you make `SharedObj` class thread safe and the `volatile` can be safely omitted. – Oleksandr Pyrohov Sep 23 '18 at 13:04

1 Answers1

1

Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility

What is the problem with visibility? CPU cores has caches, and when core wants to write data to memory, it first writes to cache, which means, even if one core thinks it writes new value to variable, other threads could still observe old value(so called 'stale data').

Entering synchronized block has following side effect: cache is invalidated - new values of variables are fetched from main memory.

Leaving synchronized block has following side effect: all cached data is flushed to main memory.

In case of your small example: image thread-1 set value sharedVar using setVar. Since this method is synchronized, value of sharedVar is flushed to main memory at the end of method. When thread-2 wants to read value using getVar, it first fetch sharedVar value from main memory - and we know, that this value is up to date. So, here volatile keyword is redundant.


By the way, reading from volatile variable has same side-effect, as leaving synchronized block: not only volatile variable value gets flushed, but also other variables; and writing to volatile variable has same side-effect as entering synchronized block: not only volatile variable value gets fetched, but also other variables;

Everything is explained perfectly in first chapters of great book Java concurrency in practice by Brian Goetz.

Flame239
  • 1,274
  • 1
  • 8
  • 20