Atomic is a type of variable that performs read, write and update in a single uninterruptible step, ensuring thread-safe operations and preventing race conditions
- It ensures data consistency without using synchronization or locks.
- It improves performance through non-blocking, lock-free operations.
- Simplify thread-safe programming for common operations like increment and compare-and-set.
Example: Without AtomicInteger
class Counter {
static int count = 0;
}
public class Geeks{
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
for (int i = 0; i < 100000; i++) {
Counter.count++;
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count = " + Counter.count);
}
}
Output
Final Count = 179864
Explanation:
- Both threads update the same shared variable.
- The count++ operation is not atomic.
- Multiple threads may read the same value simultaneously before either writes back the updated value.
- As a result, some increments are lost.
- This situation is known as a race condition.
Example: With AtomicInteger
import java.util.concurrent.atomic.AtomicInteger;
public class Geeks{
static AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Runnable task = () -> {
for (int i = 0; i < 100000; i++) {
count.incrementAndGet();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Final Count = " + count.get());
}
}
Output
Final Count = 200000
Explanation:
- Both threads update the same shared AtomicInteger.
- The incrementAndGet() method performs the increment atomically.
- No thread can interfere while the operation is being performed.
- No increments are lost.
- The final count is always correct.
How Atomic Variables Work
Atomic variables internally use a hardware-supported algorithm called Compare-And-Swap (CAS). CAS works in three steps:
- Read the current value.
- Compare it with the expected value.
- If both values match, update the value atomically.
If another thread changes the value before the update occurs, the operation fails and is retried automatically. This allows atomic variables to provide thread safety without using explicit locks.
Types of Atomic Variables in Java
Below are some commonly used atomic variable types in Java.

1. AtomicInteger
AtomicInteger provides atomic operations (increment, decrement, add, etc.) on integer values without synchronization.
import java.util.concurrent.atomic.AtomicInteger;
public class GFG{
public static void main(String[] args){
AtomicInteger count = new AtomicInteger(5);
count.incrementAndGet(); // 6
count.addAndGet(3); // 9
System.out.println("Final Value: " + count.get());
}
}
Output
Final Value: 9
2. AtomicLong
AtomicLong supports atomic operations on long values for thread-safe numeric computations.
import java.util.concurrent.atomic.AtomicLong;
public class GFG{
public static void main(String[] args) {
AtomicLong counter = new AtomicLong(100);
// adds 50, returns old value
counter.getAndAdd(50);
System.out.println("Updated Value: " + counter.get());
}
}
Output
Updated Value: 150
3. AtomicBoolean
AtomicBoolean represents a boolean value that can be atomically updated for safe flag-based operations.
import java.util.concurrent.atomic.AtomicBoolean;
public class GFG {
private static AtomicBoolean flag
= new AtomicBoolean(false);
public static void main(String[] args)
{
if (flag.compareAndSet(false, true)) {
System.out.println(
"Operation performed only once!");
}
else {
System.out.println("Already performed!");
}
}
}
Output
Operation performed only once!
4. AtomicReference
AtomicReference allows atomic read and write of object references, useful for non-primitive data.
import java.util.concurrent.atomic.AtomicReference;
public class GFG{
public static void main(String[] args){
AtomicReference<String> message
= new AtomicReference<>("Hello");
message.compareAndSet("Hello",
"Hi, from AtomicReference!");
System.out.println("Current Message: "
+ message.get());
}
}
Output
Current Message: Hi, from AtomicReference!
5. AtomicIntegerArray
AtomicIntegerArray enables atomic operations on elements of an integer array for thread-safe updates.
import java.util.concurrent.atomic.AtomicIntegerArray;
public class GFG {
public static void main(String[] args)
{
AtomicIntegerArray numbers
= new AtomicIntegerArray(new int[] { 1, 2, 3 });
numbers.incrementAndGet(
1); // Increment element at index 1
System.out.println("Array after update: "
+ numbers);
System.out.println("Value at index 1: "
+ numbers.get(1));
}
}
Output
Array after update: [1, 3, 3] Value at index 1: 3
Commonly used methods in Atomic classes
| Method | Description |
|---|---|
| get() | Returns the current value. |
| set(value) | Sets the value to the given value. |
| getAndSet(value) | Atomically sets a new value and returns the old one. |
| incrementAndGet() | Increments the value by one and returns the updated value. |
| getAndIncrement() | Increments the value by one and returns the previous value. |
| decrementAndGet() | Decrements the value by one and returns the updated value. |
| addAndGet(delta) | Adds the specified value and returns the updated result. |
| getAndAdd(delta) | Adds the specified value and returns the previous result. |
| compareAndSet(expected, update) | Atomically updates the value only if it equals the expected value. |
| lazySet(value) | Eventually sets the value (may be delayed for performance). |