Java Volatile and Atomic variables

volatile and atomic

In this article, we will learn about Volatile and Atomic variables in Java. These topics are very important for interview perspective for experienced candidates. So let’s get started :

Volatile variables:

Volatile keyword is used in java synchronization technique to achieve thread safety,basically to overcome the visibility problem.  The variables marked as volatile gets store in main memory rather than CPU cache.

In a multithreaded environment, each thread copies the variables from the main memory to CPU cache . In multi-core CPU machine, there is a huge possibility that threads work on different CPUs so each thread will copy the variable from main memory to its CPU cache . In this case,  when thread1 will make any modification in the variable, it will be reflected only in its cache so it will lead to inconsistency of data.

volatile

Volatile keyword are used to overcome the above mentioned problem i.e. to provide thread-safe variables.

Volatile variables gets stored directly into the main memory so these are thread-safe variables.

To summarize this,

  • The value of volatile variable will never be cached  locally by thread , all reads/writes will go straight to/from main memory.
  • Accessibility of these variables are same as these are enclosed in synchronized block.
  • Volatile variables overcome the visibility problem as explained in above diagram.

Simple Illustrative example of Java Volatile variable :

VolatileTest.java

 

public class VolatileTest {

private volatile int cnt = 0;

public int getCntValue() {
return cnt;
}

public void incrementCnt() {
++cnt;
}
}

In above code snippet, we have created a class VolatileTest  with a volatile variable cnt. There are two methods , one to increment the cnt variable and second to get the current value of cnt.

TestThread .java

 

public class TestThread extends Thread {

 

private final VolatileTest test;

 

public TestThread(VolatileTest test) {
this.test = test;
}

 

@Override
public void run() {

 

int oldVal = test.getCntValue();

 

System.out.println(“[Thread ” + Thread.currentThread().getName()
+ “]: Old value = ” + oldVal);

 

test.incrementCnt();

 

int newVal = test.getCntValue();

 

System.out.println(“[Thread ” + Thread.currentThread().getName()
+ “]: New value = ” + newVal);

}
}

In above code snippet, we created a new class, called TestThread, which receives an instance of the VolatileTest in its constructor. Then, during its execution, the thread prints the current value of the volatile variable, increases it by one and finally, prints the updated value of the volatile variable.

MainVolatile .java

 

public class MainVolatile {

private final static int TOTAL_THREADS = 2;

public static void main(String[] args) throws InterruptedException {

VolatileTest volatileTest = new VolatileTest();

Thread[] threads = new Thread[TOTAL_THREADS];

for(int i = 0; i < TOTAL_THREADS; ++i)

threads[i] = new TestThread(volatileTest);

for(int i = 0; i < TOTAL_THREADS; ++i)
threads[i].start();

for(int i = 0; i < TOTAL_THREADS; ++i)
threads[i].join();
}
}

 

Sample Output is shown below:

 

[Thread 10]: Old value = 0
[Thread 11]: Old value = 0
[Thread 10]: New value = 1

[Thread 11]: New value = 2

As we observe, initially, both threads print the same value. The second thread accesses and prints the latest value of the volatile variable, after both incrementCnt() operations have been applied.

Atomic variables / AtomicInteger :

Oracle introduced java.util.concurrent.atomic package that defines classes that supports the atomic operations on single variables.

Atomic operations are crucial important for overcoming the synchronization problem.

First let us understand , what is the synchronization problem and why there is a need of atomic operations :

Consider below mentioned scenario, where the counter needs to be incremented by two threads simultaneously.

Below two threads are created to increment the counter variable by +1 . Thread-1 and Thread-2 picks the counter variable value as 1 at the same time . Thread-1 incremented the value by 1 and refreshed the result as 2 but as thread-2 has already picked the previous value  of counter i.e. 1 , it incremented the value as 2, which is not correct. This is synchronization problem.

atomic variable

This problem is encountered as this is compounded operation (read and write) and it is performed on single variable.

Hence, this problem cannot be solved even by using volatile as volatile solves the visibility problem but it fails in above mentioned scenario.

java.util.concurrent.atomic package provides many classes to support the atomic operations for single variables.

This problem can be solved using AtomicInteger class present in the package java.util.concurrent.atomic.

Let’s understand, How?

This class provides many methods that supports atomic operations :

  • increment
  • incrementAndGet
  • decrementAndGet
  • addAndGet
  • compareAndSet

atomic

Simple Example of Atomic variable : 

import java.util.concurrent.atomic.AtomicInteger;

 

class AtomicCnt {

private AtomicInteger c = new AtomicInteger(0); // initialized with 0

 

public void increment() {
c.incrementAndGet();
}

 

public void decrement() {
c.decrementAndGet();
}

 

public int value() {
return c.get();

}

 

}

In above example,  we have initialize a AtomicInteger variable with the value 0. Two methods increment and decrement are calling incrementAndGet() and decrementAndGet() methods of AtomicInteger class respectively. These methods of AtomicInteger class is performing atomic operation on the single variable c rather than compounded operation and is leading to correct data increment.

That’s How Atomic variables solves the synchronization problem.

Thanks for reading this article. I hope , you like it,

For any suggestions / feedback / question / clarification, Kindly post your comments in the below comment box.

Please subscribe our news letter and connect with social media accounts and don’t miss any articles.

Happy Reading!!!

Leave a Reply

Your email address will not be published. Required fields are marked *