Atomic Operations and Classes

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 5Code language: JavaScript (javascript)

2. AtomicLong

Performs atomic operations on long values.

AtomicLong atomicLong = new AtomicLong(100L);
atomicLong.decrementAndGet(); // Atomically decrements by 1Code 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 falseCode 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.

Scroll to Top