Java Atomic Variable
An atomic variable in Java refers to a variable that can be accessed and modified in a way that guarantees thread safety without the need for explicit synchronization. This means that operations on an atomic variable are atomic, meaning they are indivisible and not subject to interference from other threads.
Java provides a package called java.util.concurrent.atomic
that includes various classes for working with atomic variables, such as AtomicInteger
, AtomicLong
, and AtomicBoolean
.
Here’s an example using AtomicInteger
:
package org.websparrow;
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicExample {
public static void main(String[] args) {
AtomicInteger atomicInt = new AtomicInteger(0);
// Increment the atomic integer atomically by multiple threads
Runnable incrementTask = () -> {
for (int i = 0; i < 10000; i++) {
atomicInt.incrementAndGet();
}
};
Thread thread1 = new Thread(incrementTask);
Thread thread2 = new Thread(incrementTask);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final value: " + atomicInt.get());
}
}
In this example, we create an AtomicInteger
called atomicInt
, and two threads increment it by 10,000 in a loop. Because AtomicInteger
provides atomic operations like incrementAndGet()
, we can safely increment it from multiple threads without worrying about synchronization issues.
Situation where you can use Atomic Variables
- Counters and Statistics: When multiple threads need to increment a shared counter or maintain statistics, using atomic variables can ensure accurate and thread-safe updates.
- Flags and Status Indicators: If you need to set and check flags or status indicators shared among threads, atomic booleans (e.g.,
AtomicBoolean
) can help prevent race conditions. - Resource Pooling: In scenarios where you manage a pool of resources (e.g., connections, threads), you can use atomic variables to track the availability of resources without requiring synchronized blocks.
- Control Structures: In situations where you need to implement custom control structures or synchronization mechanisms, atomic variables can help ensure proper coordination.
Types of Atomic Variable
Java provides several types of atomic variables in the java.util.concurrent.atomic
package. Some of the commonly used atomic variable types include:
1. AtomicInteger: Represents an integer value that can be updated atomically. It provides methods like incrementAndGet()
, decrementAndGet()
, getAndSet()
, and more for atomic operations on integers.
AtomicInteger atomicInt = new AtomicInteger(0);
atomicInt.incrementAndGet();
2. AtomicLong: Similar to AtomicInteger
, but for long values.
AtomicLong atomicLong = new AtomicLong(0L);
atomicLong.incrementAndGet();
3. AtomicBoolean: Represents a boolean value that can be updated atomically. It provides methods like getAndSet()
and compareAndSet()
for atomic operations on booleans.
AtomicBoolean atomicBoolean = new AtomicBoolean(true);
atomicBoolean.compareAndSet(true, false);
4. AtomicReference: Represents a reference to an object that can be updated atomically. This is useful for managing references to shared objects.
AtomicReference<String> atomicRef = new AtomicReference<>("Initial Value");
atomicRef.set("New Value");
5. AtomicIntegerArray: An array of integers where each element can be updated atomically.
AtomicIntegerArray atomicIntArray = new AtomicIntegerArray(5);
atomicIntArray.getAndSet(2, 42);
6. AtomicLongArray: Similar to AtomicIntegerArray
, but for long values.
AtomicLongArray atomicLongArray = new AtomicLongArray(5);
atomicLongArray.getAndSet(2, 42L);
7. AtomicReferenceArray: An array of object references where each element can be updated atomically.
AtomicReferenceArray<String> atomicRefArray = new AtomicReferenceArray<>(5);
atomicRefArray.set(2, "New Value");
Summary
These atomic variables provide thread-safe operations for their respective data types without the need for explicit synchronization. They are particularly useful in multi-threaded applications to ensure that concurrent updates are performed atomically and without data corruption.