Clean • Professional
In multi-threaded applications, multiple threads may try to read and modify the same variable at the same time. This situation can lead to race conditions, where the final result becomes unpredictable.
To solve this problem, Java provides Atomic Variables in the java.util.concurrent.atomic package.
Atomic variables allow developers to perform thread-safe operations without using synchronization or locks, which improves performance and simplifies code.
Atomic variables are special classes in Java that support atomic operations on single variables.
An atomic operation means the operation is completed in a single, indivisible step. No other thread can interrupt the operation while it is being executed.
This ensures that multiple threads can safely update the variable without causing inconsistent results.
Consider a scenario where multiple threads are incrementing the same counter.
Example without synchronization:
counter++;
This simple operation actually involves three internal steps:
If multiple threads perform these steps simultaneously, the result may become incorrect due to race conditions.
Atomic variables solve this issue by performing operations like increment, decrement, and compare-and-set atomically.
Atomic variables are available in the package:
java.util.concurrent.atomic
This package provides several classes for thread-safe atomic operations.
Some commonly used atomic classes include:
AtomicInteger is one of the most commonly used atomic classes.
It provides thread-safe operations on integer values without using synchronized blocks.
Example:
import java.util.concurrent.atomic.AtomicInteger;
AtomicInteger counter = new AtomicInteger(0);
Here, the counter is initialized with value 0.
Example:
counter.incrementAndGet();
This method increments the value by 1 and returns the updated value.
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicExample {
static AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
counter.incrementAndGet();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Counter: " + counter.get());
}
}
Output:
Final Counter: 2000
Even though multiple threads are updating the variable, the result remains correct because the operation is atomic.
AtomicInteger provides several useful methods for thread-safe operations.
| Method | Description |
|---|---|
| get() | Returns the current value |
| set() | Updates the value |
| incrementAndGet() | Increments value and returns updated value |
| getAndIncrement() | Returns current value then increments |
| decrementAndGet() | Decreases value by 1 |
| addAndGet(n) | Adds a value and returns result |
| compareAndSet(expected, newValue) | Updates value if it matches expected value |
One powerful feature of atomic variables is the Compare-And-Set (CAS) operation.
CAS works by:

Example:
AtomicInteger value = new AtomicInteger(10);
value.compareAndSet(10, 20);
System.out.println(value);
Output:
20
This operation is lock-free and very fast, which makes atomic variables highly efficient in concurrent programming.
AtomicLong works exactly like AtomicInteger, but it is used for long values.
Example:
import java.util.concurrent.atomic.AtomicLong;
AtomicLong count = new AtomicLong(100);
count.incrementAndGet();
System.out.println(count);
Output:
101
AtomicLong is useful when working with large numeric counters.
AtomicBoolean is used for thread-safe boolean operations.
Example:
import java.util.concurrent.atomic.AtomicBoolean;
AtomicBoolean flag = new AtomicBoolean(false);
flag.set(true);
System.out.println(flag.get());
Output:
true
AtomicReference is used when you want atomic operations on objects instead of primitive values.
Example:
import java.util.concurrent.atomic.AtomicReference;
AtomicReference<String> name = new AtomicReference<>("Java");
name.set("Concurrency");
System.out.println(name.get());
Output:
Concurrency
| Feature | Atomic Variables | Synchronized |
|---|---|---|
| Performance | Faster | Slower |
| Locking | Lock-free | Uses locks |
| Complexity | Simple | More complex |
| Blocking | Non-blocking | Blocking |
Atomic variables are usually more efficient than synchronized blocks for simple operations.
Atomic variables provide several benefits in concurrent programming.
Despite their advantages, atomic variables also have some limitations.
Atomic variables are useful when:
Common real-world uses include:
Atomic variables in Java provide a powerful way to handle thread-safe operations without using locks or synchronization.
Classes such as AtomicInteger, AtomicLong, AtomicBoolean, and AtomicReference allow developers to perform atomic updates efficiently in multi-threaded environments.