volatile variable in Java is a special variable that is used to signal threads, a compiler that the value of this particular variable is going to be updated by multiple threads inside the Java application.
When we make a variable volatile, we ensure that its value should always be read from the main memory and the thread should not use the cached value of that variable from its own stack.
The volatile keyword can only be applied to a variable, it can not be applied to a class or method. Using volatile keywords along with class and method will result in a compile-time error.
When to use a Volatile variable in Java?
- Any variable which is shared between multiple threads should be made volatile, to ensure that all threads must see the latest value of the volatile variable.
- A signal to the compiler and JIT to ensure that the compiler does not change ordering or volatile variables and moves them out of synchronized context.
- You want to save the cost of synchronization as volatile variables are less expensive than synchronization.
What are the differences between volatile and synchronization?
- The volatile keyword-only can apply on fields, but the synchronization keyword can apply to code blocks and methods.
- The thread cannot be blocked for waiting in case of volatile, whereas Threads can be blocked for waiting in case of synchronized.
- Volatile fields are not subject to compiler optimization, but Synchronize is subject to compiler optimization.
What does Atomic mean?
Let's say we declare a variable
int age=27;
Here we are assigning 27 to the primitive variable age, that's it. We are neither updating nor reading the age, that's why this is an atomic statement.
Is incrementing or decrementing Atomic?
The answer is no. When we perform age++ or age--, we are actually performing three operations: reading the value of age, incrementing/decrementing the age, and then writing to variable age.
Which of the following operations is Atomic?
b). Writing to a volatile int.
c). Writing to a non-volatile long.
d). Writing to a volatile long.
e). Incrementing a volatile long.
A write to an int (32-bit) variable is guaranteed to be atomic, whether it is volatile or not.
A long (64-bit) variable could be written in two separate steps, for example, on 32-bit architectures, so by default, there is no atomicity guarantee. However, if you specify the volatile modifier, a long variable is guaranteed to be accessed atomically.
The increment operation is usually done in multiple steps (retrieving a value, changing it, and writing back), so it is never guaranteed to be atomic, whether the variable is volatile or not. If you need to implement the atomic increment of a value, you should use classes AtomicInteger, AtomicLong, etc.
Explain concurrency utils (Atomic packages).
java.util.concurrent.atomic is a small toolkit of classes to perform atomic operations. They support lock-free, thread-safe programming on single variables.
Atomic variables in Java provide the same memory semantics as a volatile variable but with the added feature of making non-atomic operations atomic.
Instances of Atomic classes (AtomicBoolean, AtomicInteger, AtomicLong, and AtomicReference) maintain values that are accessed and updated using methods otherwise available for fields using associated atomic VarHandle operations.
FYI, the classes of Atomic package are not general-purpose replacements for java.lang.Integer and related classes. They do not define methods such as equals, hashCode, and compareTo, because atomic variables are expected to be mutated, they are poor choices for hash table keys.
Internally, the atomic classes make heavy use of compare-and-swap (CAS), an atomic instruction directly supported by most modern CPUs. Those instructions usually are much faster than synchronizing via locks.
What is the difference between volatile and AtomicInteger in Java concurrency?
Let's say we have a simple method incrementCounter(), which increments the variable counter:
private int counter;public int incrementCounter() {
return counter++;
}
public int getCounter() {
return counter;
}
This code will work correctly in a single-threaded program but will give incorrect results when used in multi-threaded execution.
Suppose multiple threads are reading the counter value by calling getCounter(). The value of the counter is simultaneously updated by threads. Every time any thread calls getCounter(), it should get the latest value instead of getting the value from the cache. In such scenarios, the counter variable should be declared as volatile. e.g:
volatile int counter;
Volatile variables are those variables that are not optimized by the compiler while parsing the code.
Volatile indicates that this variable value may change every time and is not stored in the cache. If we try to access a volatile variable twice, it will be accessed twice from the hardware memory, not the cache. In this way, the volatile variable avoids optimisation.
Volatile is used, generally to solve the visibility problem.
Now let's say multiple threads are updating the counter by calling incrementCounter(). The counter++ i.e counter=counter+1 is a compound operation, which involves two sub-operations: 1). Read the value of the counter, 2). Increment it by one and write the value.
Two threads T1 and T2 are trying to increment the counter (let's say the value of the counter is 0) at the same time. There might be a chance both T1 and T2 call incrementCounter() at the same time, and both get the value as 0. And then both threads increment it since both Threads have a value as 0, the value of the counter after increment will be 1, instead of 2.
This issue can be handled by making using synchronization. But there is one more option available. We can use AtomicInteger instead of int.
Atomic variables are variables that use a low-level CPU operation. It provides non-blocking variable change by multiple threads. The compound operations with such variables are performed automatically without the use of synchronization. The memory effect is the same as a volatile variable. The most important advantage of an atomic variable is that it avoids deadlocks.
AtomicInteger counter=new AtomicInteger(0);
counter.incrementAndGet();//increment and return the value
counter.decrementAndGet();//decrement and return the value
counter.getAndIncrement();//get the current value and then increment it by one
counter.getAndDecrement();//get the current value and then decrement it by one
counter.getAndSet(5);//set the value to 5
counter.compareAndSet(5, 6); //if the value is 5, set it to 6
Volatile is used, generally to solve the visibility problem.
Now let's say multiple threads are updating the counter by calling incrementCounter(). The counter++ i.e counter=counter+1 is a compound operation, which involves two sub-operations: 1). Read the value of the counter, 2). Increment it by one and write the value.
Two threads T1 and T2 are trying to increment the counter (let's say the value of the counter is 0) at the same time. There might be a chance both T1 and T2 call incrementCounter() at the same time, and both get the value as 0. And then both threads increment it since both Threads have a value as 0, the value of the counter after increment will be 1, instead of 2.
This issue can be handled by making using synchronization. But there is one more option available. We can use AtomicInteger instead of int.
Atomic variables are variables that use a low-level CPU operation. It provides non-blocking variable change by multiple threads. The compound operations with such variables are performed automatically without the use of synchronization. The memory effect is the same as a volatile variable. The most important advantage of an atomic variable is that it avoids deadlocks.
AtomicInteger counter=new AtomicInteger(0);
counter.incrementAndGet();//increment and return the value
counter.decrementAndGet();//decrement and return the value
counter.getAndIncrement();//get the current value and then increment it by one
counter.getAndDecrement();//get the current value and then decrement it by one
counter.getAndSet(5);//set the value to 5
counter.compareAndSet(5, 6); //if the value is 5, set it to 6
A volatile variable is generally used when the value of the variable does not depend on its previous value. Hence volatile variables are suitable for boolean variables. Whereas atomic variables can be used for variables where the value of the variable depends on its previous value like increment or decrement operations.
Can we make the array volatile in Java?
Yes, it is possible to make an array volatile in Java, but only the reference which is pointing to an array, not the whole array. However, there is a catch.
In Java, the volatile keyword is used to indicate that a variable's value may be changed by multiple threads simultaneously. It is a modifier that is applied to instance variables of a class. When a variable is declared as volatile, it guarantees that any thread that reads the field sees the most recent modification made by any other thread.
However, it's important to note that the volatile keyword does not apply to arrays as a whole in Java. We can only use volatile with individual array elements if they are declared as volatile.
The volatile keyword applies only to instance variables of a class and guarantees visibility and ordering of reads and writes to that variable. It does not apply to arrays directly, i.e. the volatile keyword does not apply to arrays as a whole in Java.
Let's say we have the variable myArray, which is declared as an array of integers, and it is marked as volatile. We have two methods modifyArray() and printArray() to modify and print the array. This means that changes made to individual elements of the array by one thread will be visible to other threads.
private volatile int[] myArray = new int[5];
If the purpose is to provide a memory visibility guarantee for individual indices of the array, volatile is of no practical use to us. To make thread-safe, we would typically use other synchronization mechanisms such as synchronized blocks or methods, or use the higher-level concurrency utilities provided by the java.util.concurrent packages, such as ReentrantLock or ReadWriteLock.
How AtomicInteger work internally? Why is AtomicInteger class better than a synchronized counter class?
Java 5 introduced java.util.concurrent.atomic package that supports lock-free thread-safe programming on single variables.
AtomicInteger class of atomic package uses a combination of volatile and CAS (compare and swap) to achieve thread-safety for Integer Counter. It is non-blocking in nature and thus highly usable in writing high throughput concurrent data structures that can be used under low to moderate thread contention.
Explain Compare-And-Swap (CAS).
It's an atomic instruction by which we can achieve synchronization. It compares the contents of a memory location to a given value and, only if they are the same, modifies the contents of that memory location to a given new value. All this is done as a single atomic operation. If the value has been updated by another thread at the same time, the write will fail.
The AtomicInteger internally uses sun. misc.Unsafe class.
'value' is declared 'volatile', which makes sure the variable acts synchronized. It also means every thread needs to read it from memory rather than from its thread cache, and every modification will be flushed into memory immediately.
With the use of unSafe instance, the value of the volatile integer is manipulated atomically at the hardware level without using synchronization. The 'valueOffset' represents the memory address where the value needs to be updated.
Can we access Unsafe directly?
Well no. Java makes Unsafe unavailable for direct access. If you run the following code you will get an exception.
Unsafe unsafe = Unsafe.getUnsafe();
This reason is in the implementation of getUnsafe.
When the JVM is started, three class loaders are used:
Constructor < Unsafe > constructor = Unsafe.class.getDeclaredConstructor();
constructor.setAccessible(true);
Unsafe unsafe = constructor.newInstance();
Unsafe unsafe = Unsafe.getUnsafe();
This reason is in the implementation of getUnsafe.
When the JVM is started, three class loaders are used:
- The bootstrap class loader loads the core Java libraries[5] located in the
/jre/lib directory. This class loader, which is part of the core JVM, is written in native code. - The extensions class loader loads the code in the extensions directories (
/jre/lib/ext,[6] or any other directory specified by the java.ext.dirs system property). It is implemented by the sun.misc.Launcher$ExtClassLoader class. - The system class loader loads code found on java.class.path, which maps to the CLASSPATH environment variable. This is implemented by the sun.misc.Launcher$AppClassLoader class.
Constructor < Unsafe > constructor = Unsafe.class.getDeclaredConstructor();
constructor.setAccessible(true);
Unsafe unsafe = constructor.newInstance();
Also Check: Java Thread Interview Questions & Answers
If you enjoy our content and want to support us, please consider donating via gpay, phonepay or paytm on +91 9920600280. Also, I’d appreciate it if you’d buy me a coffee☕
Keep learning and growing!
-K Himaanshu Shuklaa..
thank you shukla sir
ReplyDeleteI must say you are an amazing blogger
ReplyDelete