Volatile in Java

Volatile Keyword Quick Read:

  • can be applied on variables only and not methods and classes
  • Guarantees the visibility of variables among thread. (Not allowing to cache a copy variables)
  • JVM optimization/re-ordering/caching does not work on volatile variables
  • Should be used when only one thread writes the volatile variables and multiple thread reads it, volatile will not work if multiple threads are writing this variables.(Atomic should be used in this case)

About Volatile in java

  • Volatile guarantees that the a share object is not cached by a Thread executing core and it is read from the main memory.
  • Volatile does not guarantee concurrency (for read and write anomalies) but guarantees that the object is visible across threads by keeping that value in the main memory.
  • Explaination with example below

Example :

package com.demo.threadDemo;

import java.util.concurrent.TimeUnit;

public class CommonObjectUseDemo {
	public static void main(String[] args) {
		Common commonObj = new Common();
		commonObj.setRun(true);
		Thread t1 = new Thread( new ThreadExample1(commonObj));
		Thread t2 = new Thread( new TerminatingThread(commonObj));
		t1.start();
		t2.start();
	}
}
class ThreadExample1 implements Runnable{
	int x;
	private Common common;
	ThreadExample1(Common common){
		this.common = common;
	}
	@Override
	public void run() {
		while(common.isRun()) {
			try {
				TimeUnit.MILLISECONDS.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("Value : "+x++);
		}
	}
}
class TerminatingThread implements Runnable{
	private Common common;
	
	public TerminatingThread(Common common) {
		this.common = common;
	}

	@Override
	public void run() {
		try {
			TimeUnit.SECONDS.sleep(10);
			System.out.println("Setting to false");
			common.setRun(false);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
}
class Common{
	private boolean run;
	public boolean isRun() {
		return run;
	}
	public void setRun(boolean run) {
		this.run = run;
	}
}
  • In above example,
    • Thread t1 – Just prints incremented value by checking if common object run value is true
    • Thread t2 – Sets the common object run value to false
  • So once Thread t1 and Thread t2 runs, object commonObj is shared between both
  • The expectation is that Thread t2 sets the run value to false and this Terminates the initifte running Thread t1. (Many of the time it may work like this but there is not guarantee, for the purpose of guarantee Volitile keyword was introduced, read below)
  • Tho object commonObj is shared between both Threads it is not guaranteed by the operating system that Thread t1 and Thread t2 share it, the commonObj could be cached in the cache of the executing code.
  • So core 1 executing Thread t1 has it own commonObj copy in Core 1’s L1/L2 cache
  • So core 2 executing Thread t2 has it own commonObj copy in Core 2’s L1/L2 cache
  • Now even tho core 2 updates the run value to false, it is updated in its own cache
  • And the thread executing in core 1 will never refer the commonObj in Core 2’s cache
  • Hence the Thread t1 will be running neverendingly
  • To avoid this problem and guarantee the commonObj or any other common resources are not cache inside the L1/L2/L3 cache of the core we use the keyword volatile

Reference :

Leave a Comment