Skip to main content

AtomicInteger Class

The AtomicInteger class can be thought of as an atomic implementation of an Integer because it holds an integer value and provides atomic operations on it. It can be initialized with a value or left uninitialized, with the default value being 0.

The most commonly used methods are get() (returns the integer value), set(x) (sets the value to x), compareAndSet(x, y) (compares the integer with x, and if the two values are equal, sets the value to y), addAndGet(delta) / getAndAdd(delta) (increments the current value by delta and returns the new value or the old one, respectively). An example of using these methods can be seen below.

AtomicInteger nr = new AtomicInteger(4);
System.out.println(nr.get()); // 4

if (nr.compareAndSet(4, 7))
System.out.println(nr.get()); // nr becomes 7

System.out.println(nr.addAndGet(2)); // adds 2, then it becomes 9

nr.set(1);
System.out.println(nr.get()); // 1

Using AtomicInteger is more advantageous in terms of performance (specifically in terms of execution times) than using locks (synchronized blocks) because with locks, there is overhead created by acquire() (lock()) and release() (unlock()), as can be observed below.

Example
import java.util.concurrent.atomic.AtomicInteger;

public class Main {
public static final int size = 1000000;
public static final int noThreads = 8;
public static int[] arr = new int[size];
public static final Object lock = new Object();

public static void main(String[] args) {
for (int i = 0; i < size; i++) {
arr[i] = i;
}

Thread[] properThreads = new Thread[noThreads];
Thread[] atomicThreads = new Thread[noThreads];

long startTime = System.nanoTime();
for (int i = 0; i < properThreads.length; i++) {
properThreads[i] = new ProperThread(i);
properThreads[i].start();
}

for (Thread properThread : properThreads) {
try {
properThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
long stopTime = System.nanoTime();
System.out.println("With locks = " + (stopTime - startTime));

startTime = System.nanoTime();
for (int i = 0; i < atomicThreads.length; i++) {
atomicThreads[i] = new AtomicThread(i);
atomicThreads[i].start();
}

for (Thread atomicThread : atomicThreads) {
try {
atomicThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
stopTime = System.nanoTime();
System.out.println("With AtomicInteger = " + (stopTime - startTime));

System.out.println("Atomic sum = " + AtomicThread.sum.get());
System.out.println("Locking sum = " + ProperThread.sum);
}
}

class AtomicThread extends Thread {
public static AtomicInteger sum = new AtomicInteger(0);
private final int id;

public AtomicThread(int id) {
this.id = id;
}

@Override
public void run() {
int start = id * (int) Math.ceil((double) Main.size / Main.noThreads);
int end = Math.min(Main.size, (id + 1) * (int) Math.ceil((double) Main.size / Main.noThreads));
for (int i = start; i < end; i++) {
sum.getAndAdd(Main.arr[i]);
}
}
}

class ProperThread extends Thread {
public static int sum = 0;
private final int id;

public ProperThread(int id) {
this.id = id;
}

@Override
public void run() {
int start = id * (int) Math.ceil((double) Main.size / Main.noThreads);
int end = Math.min(Main.size, (id + 1) * (int) Math.ceil((double) Main.size / Main.noThreads));
for (int i = start; i < end; i++) {
synchronized (Main.lock) {
sum += Main.arr[i];
}
}
}
}

Java provides atomic implementations for all primitive types and more (AtomicBoolean, AtomicLong, AtomicIntegerArray, etc.). You can find more information in the Java documentation.