Do you think IIT Guwahati certified course can help you in your career?
No
Introduction
In a world where software applications are increasingly multithreaded, ensuring thread safety and data consistency has become a critical challenge for developers. Traditional synchronization techniques, like using synchronized blocks or locks, often come with performance costs and can lead to complex, error-prone code. This is where Java's atomic variables come into play. Atomic variables are part of the java.util.concurrent.atomic package and provide a lock-free, thread-safe way to perform operations on single variables.
We have eight primitive or native data types in Java, namely,
int
short
long
byte
float
double
boolean
char
What are atomic variables Java?
Atomic variables in Java are variables that provide atomicity guarantees for certain operations performed on them. Atomicity means that these operations are indivisible and appear as if they occur instantaneously, without interference from other threads. In Java, atomic variables are part of the java.util.concurrent package and are used for concurrent programming to ensure thread safety without explicit synchronization.
Java Atomic Classes
Java Atomic Classes are a set of classes provided by the java.util.concurrent.atomic package that encapsulate primitive data types and provide atomic operations for concurrent programming. These classes ensure thread safety without the need for explicit synchronization mechanisms such as locks or synchronized blocks.
Parameters
Description
Atomic Classes
Java provides atomic classes like AtomicInteger, AtomicLong, AtomicBoolean, and AtomicReference. These classes encapsulate primitive types or references and enable thread-safe, atomic operations.
Atomic Operations
Atomic classes support methods like get(), set(), getAndSet(), compareAndSet(), incrementAndGet(), and decrementAndGet(), ensuring operations are executed atomically, even in multithreaded environments.
Compare-and-Set (CAS)
Uses the Compare-and-Set (CAS) mechanism to achieve atomicity. CAS updates a variable's value only if its current value matches an expected value, ensuring safe and efficient non-blocking synchronization.
Thread Safety
Atomic classes ensure thread-safe access to shared variables without requiring explicit locks or synchronization, simplifying code and reducing the potential for deadlocks.
Performance
While atomic operations are slightly slower than non-atomic operations, they are faster and more scalable than traditional synchronization mechanisms in many scenarios, making them ideal for performance-critical applications.
Why use Atomic Variables in Java?
The Atomic Variables in Java come in handy in the case of concurrency. For instance, let us consider an example where we have to count the number of times a loop is running for multiple threads.
Java
Java
class threadCount extends Thread { int total = 0; // Non-atomic integer
public void run() { int max = 100000; for (int i = 0; i < max; i++) { total++; // Increment the non-atomic integer } } }
public class Main { public static void main(String args[]) throws InterruptedException { threadCount count = new threadCount(); Thread first = new Thread(count, "First"); Thread second = new Thread(count, "Second");
first.start(); second.start();
first.join(); second.join();
// Print the result that varies due to race condition System.out.println("Loop count without using Atomic Variables in Java: " + count.total); } }
You can also try this code with Online Java Compiler
Loop count without using Atomic Variables in Java: 133060
As is clearly visible from the above output, the program gives a different outcome for each execution. But is it supposed to happen? No, the program should return 200000 as the output for each execution. So why does it happen? The fault occurs because of concurrency. At times the threads may execute simultaneously, causing a write problem. We can overcome this using two methods,
We can solve the issue of concurrency using the synchronization function in Java.
Java
Java
import java.io.*; import java.util.*; class threadCount extends Thread { int total = 0; public synchronized void run(){ int max = 100000; for (int i = 0; i < max; i++) { total++; } } }
public class usingSync { public static void main(String args[])throws InterruptedException{ threadCount count = new threadCount(); Thread first = new Thread(count, "First"); Thread second = new Thread(count, "Second"); first.start(); second.start(); first.join(); second.join(); System.out. println("Loop count using Synchronisation: "+count.total); } }
You can also try this code with Online Java Compiler
As you can see, no matter how many times the program is executed, it returns the same and correct output. We can also achieve this using the Atomic Variables in Java.
There are various methods present in Atomic Variables in Java, for example.
get(): This method is used to fetch the current value of the Atomic Variable in Java.
addAndGet(int val): This method is used to atomically add the given value to the current value of the Atomic Variable in Java.
decrementAndGet(): This method is used to decrease the value of the variable.
Users can create an instance of the Atomic Variable class and call these functions directly.
Let us look at how to implement the above problem using Atomic Variables in Java,
Java
Java
import java.util.concurrent.atomic.AtomicInteger; class threadCount extends Thread { //creating an instance of Atomic Variable Class AtomicInteger total; threadCount(){ total = new AtomicInteger(); } public void run(){ int max = 100000; for (int i = 0; i < max; i++) { //Calling the addAndGet function total.addAndGet(1); } } }
public class usingAtomic { public static void main(String args[])throws InterruptedException{ threadCount count = new threadCount(); Thread first = new Thread(count, "First"); Thread second = new Thread(count, "Second"); first.start(); second.start(); first.join(); second.join(); System.out. println("Loop count using Atomic Variables in Java: "+count.total); } }
You can also try this code with Online Java Compiler
The atomic concept in Java refers to operations that are indivisible and appear as if they occur instantaneously, ensuring thread safety without explicit synchronization.
What is atomic in multithreading?
In multithreading, atomic refers to operations that are performed atomically, without interference from other threads, ensuring thread safety.
Are the Atomic Variables in Java thread-safe?
Yes, Atomic Variables in Java are thread-safe. They ensure thread safety by providing atomic operations without the need for explicit synchronization mechanisms.
Why do we use atomic variables in Java?
We use atomic variables in Java to ensure thread-safe, lock-free operations on shared variables in multithreaded environments. They provide efficient and non-blocking synchronization using Compare-and-Set (CAS) operations, simplifying code and avoiding performance overhead of traditional locking mechanisms.
What package is associated with Atomic Variables in Java?
The Atomic Variable class can be imported into your Java code using the java.util.concurrent.atomic package.
Conclusion
Atomic variables in Java are a powerful tool for achieving thread-safe and efficient operations in multithreaded applications. By leveraging the Compare-and-Set (CAS) mechanism, they eliminate the need for traditional locking, reducing complexity and enhancing performance. Whether you're managing counters, flags, or shared references, atomic classes provide a clean and effective way to handle concurrency challenges.