What is volatile?
When a variable is defined using volatile modifier, it is guaranteeing that it will not be cached by threads and threads will see the updated value immediately. Without volatile, readers could see some non-updated value.
Let’s see it with an example.
VolatileEx.java
package com.sample.app.threads;
public class VolatileEx extends Thread {
boolean flag = true;
public void run() {
while (flag) {
}
System.out.println("Came out of the loop");
}
public static void main(String args[]) throws Exception {
VolatileEx t1 = new VolatileEx();
t1.start();
Thread.sleep(1000);
t1.flag = false;
System.out.println("Flag is set to " + t1.flag);
}
}
When you ran above application, program goes to infinite loop. Even you set the flag to false, thread keeps using its local copy of the variable flag ( which is true). This problem is solved by volatile keyword.
Define the variable flag using volatile modifier.
volatile boolean flag = true;
VolatileEx.java
package com.sample.app.threads;
public class VolatileEx extends Thread {
volatile boolean flag = true;
public void run() {
while (flag) {
}
System.out.println("Came out of the loop");
}
public static void main(String args[]) throws Exception {
VolatileEx t1 = new VolatileEx();
t1.start();
Thread.sleep(1000);
t1.flag = false;
System.out.println("Flag is set to " + t1.flag);
}
}
Output
Came out of the loop Flag is set to false
Atomic references
java.util.concurrent.atomic package provides a small toolkit of classes that support lock-free thread-safe programming on single variables.
From the Java documentation (https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/atomic/package-summary.html), I do not see any difference between volatile and atomic references. AtomicReference get and set has the same Java Memory model semantics as a volatile field.
If you look at the code of AtomicReference, it internally use a volatile variable.
public class AtomicReference<V> implements java.io.Serializable {
private volatile V value;
.......
.......
}
When to choose what?
If your use case is simple set and get operations, then you can go for volatile modifier. But if you want to have additional CAS (compare-and-swap) functionality, then you can go for atomic references. In computer science, compare-and-swap (CAS) is an atomic instruction used in multithreading to achieve synchronization. It compares the contents of a memory location with a given value and, only if they are the same, modifies the contents of that memory location to a new given value.
CASDemo.java
package com.sample.app.threads;
import java.util.concurrent.atomic.AtomicInteger;
public class CASDemo {
public static void main(String args[]) {
AtomicInteger atomicInteger = new AtomicInteger(10);
System.out.println("value " + atomicInteger.get());
if(atomicInteger.compareAndSet(10, 21)) {
System.out.println("\nValue updated successfully!!!!");
System.out.println("value " + atomicInteger.get());
}else {
System.out.println("\nValue is not updated successfully!!!!");
System.out.println("value " + atomicInteger.get());
}
if(atomicInteger.compareAndSet(10, 21)) {
System.out.println("\nValue updated successfully!!!!");
System.out.println("value " + atomicInteger.get());
}else {
System.out.println("\nValue is not updated successfully!!!!");
System.out.println("value " + atomicInteger.get());
}
}
}
Output
value 10 Value updated successfully!!!! value 21 Value is not updated successfully!!!! value 21
You may like
Java: How to replace a value in ArrayList or LinkedList
Why do we declare logger with static and final?
How to check the type of a variable in Java?
No comments:
Post a Comment