Java Concurrency & The Volatile Keyword

Java Concurrency & the Volatile Keyword
Java Concurrency & the Volatile Keyword

Introduction

Java is one of the most used languages by developers around the world. Billions of devices run on Java. So, it becomes increasingly important to keep track of some of the most useful features of this. In this article, we will be briefly discussing the volatile keyword in Java concurrency control.

Volatile is a keyword used to apply concurrency control over fields and variables. When the volatile keyword is declared, it makes the field or variable which is being accessed by one thread, and the changes made by it is immediately shown to all other subsequent threads accessing it.

Now read the best books for starting your careers in JavaScripts 2021.

Why do we need this keyword?

Suppose we have a variable that is consequently accessed by multiple threads, without the synchronisation this process will simply depend upon the order in which the threads access the variable. Hence, the final value of the variable will be based on the order of threads accessing it.

In order to prevent this unpredictable outcome, we need to use some kind of synchronisation mechanism, which includes, locking objects, volatile keyword etc.

Practical Problem

/* package whatever; // don't place package name! */

import java.util.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
	public class example implements Runnable {
	private Account acct = new Account();
	public static void main(String[] args) {
		AccountTesting r = new AccountTesting();
		Thread one = new Thread(r);
		Thread two = new Thread(r);
		one.setName("Aniruddha");
		two.setName("Nisha");
		one.start();
		two.start();
	}
	@Override
	public void run() {
		for (int x = 0; x < 10; x++) {
			makeWithdrawal(10);
			if (acct.getBalance() < 0) {
				System.out.println("overdrawn!");
			}
		}
	}
	private void makeWithdrawal(int amt) {
		if (acct.getBalance() >= amt) {
			System.out.println(Thread.currentThread().getName() + " is withdrawn");
			try {
				Thread.sleep(100);
			} catch (InterruptedException ex) {
			}
			acct.withdraw(amt);
			System.out.println(Thread.currentThread().getName() + " complete withdrawal");
		} else {
			System.out.println("Not enough in account for " + Thread.currentThread().getName() + " to withdraw " + acct.getBalance());
		}
	}
}

class Account {
	private int balance = 50;
	public int getBalance() {
	return balance;
	}
	public void withdraw(int amount) {
	balance = balance - amount;
	}
}}

In the above programme, it is basically an account transaction problem, where our final account balance is dependent on the order in which withdraw and deposit happens from one account to another. Well, the idea is when one state is being processed the compiler if calls the cache for faster operation, then we know that in a cache the most recently used value is present. This will create a confusion.

The modified version of the programme can be given as:

public class SynchronizedAccountTesting implements Runnable {
	private Account acct = new Account();
	public static void main(String[] args) {
		SynchronizedAccountTesting r = new SynchronizedAccountTesting();
		Thread one = new Thread(r);
		Thread two = new Thread(r);
		one.setName("Aniruddha");
		two.setName("Nishant");
		one.start();
		two.start();
	}
	@Override
	public void run() {
		for (int x = 0; x < 10; x++) {
			makeWithdrawal(10);
			if (acct.getBalance() < 0) {
				System.out.println("overdrawn!");
			}
		}
	}
	private synchronized void makeWithdrawal(int amt) {
		if (acct.getBalance() >= amt) {
			System.out.println(Thread.currentThread().getName() + "  to withdraw");
			try {
				Thread.sleep(100);
			} catch (InterruptedException ex) {
			}
			acct.withdraw(amt);
			System.out.println(Thread.currentThread().getName() + " complete withdrawal");
		} else {
			System.out.println("Not enough in account for " + Thread.currentThread().getName() + " to withdraw " + acct.getBalance());
		}
	}
}
class Account {
	private int balance = 50;
	public int getBalance() {
	return balance;
	}
	public void withdraw(int amount) {
	balance = balance - amount;
	}
}

This eliminates the error for concurrent access which is why we need synchronisation.

Volatile

It is a lightweight form of synchronisation that controls the visibility and ordering for accessing elements by multiple threads. It can also be referred as a field modifier. It ensures that any changes made to the field are directly available for the subsequent threads to process upon.

Declaring a shared variable as volatile provides visibility to multiple threads. It also limits the reordering accesses by preventing compiler and runtime code order.

The internal function of volatile is basically to cause read and writes to be accompanied by another CPU instruction called memory barrier.

Some drawbacks

  • The semantics of volatile is not as strong as locking and hence might not provide atomicity.
  • It might cause thread contention which is basically the concurrent of a resource by multiple threads.
  • Code is a bit more complicated than normal locks.

Use of Volatile keyword

It is referred in the JCIP book of instructions for Java:

  • When multiple threads can update the value of the field.
  • The variable is not a part of other invariants in different states.
  • Locking is not provided for any other reason when a field is being accessed.

Frequently Asked Questions

Can we use volatile with synchronised keyword?

We can use it but it is mostly dependent on situation.

Does volatile keyword apply to an object?

No, it only applies to object reference or primitive type.

Can thread safety be provided by volatile keyword?

It is also dependent on the technique in which they are being implemented and hence developer dependent.

Does it improve the thread performance?

Well, synchronisation actually have performance disadvantages but provide other benefits, obviously there will be tradeoffs.

Conclusion

So, we can say that volatile is a faded version of synchronisation than locking which is actually faster than locking but it might provide less thread safety. It is basically an alternative to locking and can also be used with other synchronisation methods but usually, one method is enough for a shared state.

Hope this article clears a lot of doubts in java concurrency control and helps aspiring developers and programmers.

Understand the difference between Java and other programming languages.

Happy Learning!!

By Aniruddha Guin