Java provides atomic operations through classes in the java.util.concurrent.atomic package. These classes ensure that operations on variables are performed atomically without needing explicit synchronization.
Atomic operations are actions performed in a single step without interference from other threads. This means that an atomic operation is indivisible and uninterruptible, guaranteeing data integrity even in multi-threaded environments.
Why Atomic OperationsÂ
When multiple threads operate on shared data, there’s a risk of race conditions, where the final outcome depends on the timing of thread execution. Atomic operations eliminate this risk by ensuring that no thread sees an intermediate or inconsistent state.
Java’s Atomic Classes (from java.util.concurrent.atomic)
Java provides a set of atomic classes that support lock-free, thread-safe programming on single variables. These classes internally use low-level CPU instructions  for atomicity, instead of traditional synchronization mechanisms like synchronized
.
Here are the most common atomic classes:
1. AtomicInteger
Performs atomic operations on int
values.
AtomicInteger atomicInt = new AtomicInteger(0);
atomicInt.incrementAndGet(); // Atomically increments by 1
atomicInt.addAndGet(5); // Atomically adds 5
Code language: JavaScript (javascript)
2. AtomicLong
Performs atomic operations on long
values.
AtomicLong atomicLong = new AtomicLong(100L);
atomicLong.decrementAndGet(); // Atomically decrements by 1
Code language: JavaScript (javascript)
3. AtomicBoolean
For atomic operations on boolean values.
AtomicBoolean atomicBool = new AtomicBoolean(false);
atomicBool.compareAndSet(false, true); // Atomically sets to true if current is false
Code language: JavaScript (javascript)
 4. AtomicReference<T>
  Allows atomic operations on object references.
AtomicReference<String> ref = new AtomicReference<>("Hello");
ref.compareAndSet("Hello", "World"); // Atomically replaces "Hello" with "World"
Code language: JavaScript (javascript)
 5.AtomicIntegerArray, AtomicLongArray, AtomicReferenceArrayÂ
  These classes provide atomic operations on arrays of integers, longs, and object references respectively.
  They support operations like get, set, compareAndSet, etc.
AtomicIntegerArray atomicIntArray = new AtomicIntegerArray(10);
atomicIntArray.getAndIncrement(5);
Code language: JavaScript (javascript)
import java.util.concurrent.atomic.AtomicReferenceArray;
public class AtomicReferenceArrayDemo {
public static void main(String[] args) {
// Create an AtomicReferenceArray with 3 elements
AtomicReferenceArray<String> riverArray = new AtomicReferenceArray<>(3);
// Set initial values
riverArray.set(0, "Ganga");
riverArray.set(1, "Yamuna");
riverArray.set(2, "Saraswati");
// Print original values
System.out.println("Original Rivers:");
for (int i = 0; i < riverArray.length(); i++) {
System.out.println(riverArray.get(i));
}
// Atomically update value at index 1 (if current is "Yamuna")
boolean updated = riverArray.compareAndSet(1, "Yamuna", "Godavari");
// Display result of the update
System.out.println("\nUpdate at index 1 successful: " + updated);
// Print updated values
System.out.println("\nUpdated Rivers:");
for (int i = 0; i < riverArray.length(); i++) {
System.out.println(riverArray.get(i));
}
}
}
Code language: JavaScript (javascript)
Common Atomic Methods
Method | Description |
---|---|
get() |
Gets the current value atomically |
set(value) |
Sets a new value atomically |
compareAndSet(expected, newValue) |
Sets to newValue if current value equals expected |
getAndIncrement() |
Atomically returns the current value and increments |
incrementAndGet() |
Atomically increments and returns the new value |
lazySet(value) |
Eventually sets to the new value (more efficient than set ) |
Program
This program demonstrates the use of various atomic classes provided in the java.util.concurrent.atomic
package. The program should illustrate how atomic operations can be performed on different data types such as integers, longs, booleans, and arrays safely and efficiently in a multithreaded environment.
//AllAtomicClassesExample.java import java.util.concurrent.atomic.*; public class AllAtomicClassesExample { public static void main(String[] args) { // AtomicInteger example AtomicInteger atomicInt = new AtomicInteger(0); // Increment operation System.out.println("Initial value of atomicInt: " + atomicInt.get()); atomicInt.incrementAndGet(); System.out.println("After incrementAndGet(): " + atomicInt.get()); // Compare and set operation int expectedValue = 1; int newValue = 10; boolean exchanged = atomicInt.compareAndSet(expectedValue, newValue); System.out.println("After compareAndSet(" + expectedValue + ", " + newValue + "): " + atomicInt.get()); System.out.println("Exchanged? " + exchanged); // AtomicLong example AtomicLong atomicLong = new AtomicLong(1000); // Get current value System.out.println("\nInitial value of atomicLong: " + atomicLong.get()); // Add and get operation long delta = 500; long updatedValue = atomicLong.addAndGet(delta); System.out.println("After addAndGet(" + delta + "): " + updatedValue); // Get and add operation long currentValue = atomicLong.getAndAdd(200); System.out.println("After getAndAdd(200): " + atomicLong.get()); System.out.println("Previous value returned by getAndAdd(): " + currentValue); // AtomicBoolean example AtomicBoolean atomicBoolean = new AtomicBoolean(true); // Get current value System.out.println("\nInitial value of atomicBoolean: " + atomicBoolean.get()); // Compare and set operation boolean expectedBoolean = true; boolean newBoolean = false; exchanged = atomicBoolean.compareAndSet(expectedBoolean, newBoolean); System.out.println("After compareAndSet(" + expectedBoolean + ", " + newBoolean + "): " + atomicBoolean.get()); System.out.println("Exchanged? " + exchanged); // AtomicReference example AtomicReference<String> atomicReference = new AtomicReference<>("Hello"); // Get current value System.out.println("\nInitial value of atomicReference: " + atomicReference.get()); // Compare and set operation String expectedString = "Hello"; String newString = "World"; exchanged = atomicReference.compareAndSet(expectedString, newString); System.out.println("After compareAndSet(" + expectedString + ", " + newString + "): " + atomicReference.get()); System.out.println("Exchanged? " + exchanged); // AtomicIntegerArray example int[] array = {1, 2, 3, 4, 5}; AtomicIntegerArray atomicIntArray = new AtomicIntegerArray(array); // Get and set operation int index = 2; int newValueAtIndex = 10; int oldValueAtIndex = atomicIntArray.getAndSet(index, newValueAtIndex); System.out.println("\nAfter getAndSet(" + index + ", " + newValueAtIndex + "): " + atomicIntArray); System.out.println("Old value at index " + index + ": " + oldValueAtIndex); } } /* C:\>javac AllAtomicClassesExample.java C:\>java AllAtomicClassesExample Initial value of atomicInt: 0 After incrementAndGet(): 1 After compareAndSet(1, 10): 10 Exchanged? true Initial value of atomicLong: 1000 After addAndGet(500): 1500 After getAndAdd(200): 1700 Previous value returned by getAndAdd(): 1500 Initial value of atomicBoolean: true After compareAndSet(true, false): false Exchanged? true Initial value of atomicReference: Hello After compareAndSet(Hello, World): World Exchanged? true After getAndSet(2, 10): [1, 2, 10, 4, 5] Old value at index 2: 3 */
Atomic operations and classes in Java provide a robust and efficient way to perform thread-safe computations without explicit synchronization. By leveraging classes like AtomicInteger
, AtomicLong
, AtomicBoolean
, AtomicReference
, and array-based variants, developers can ensure atomicity and visibility of shared variables, reducing the complexity and overhead associated with locks. These classes are essential tools in high-performance concurrent applications, enabling safe and scalable updates to shared resources in multithreaded environments.