increment operator

Thread-safe alternative to i++

Thread-safe alternative to i++quiz

As we already know that ++ operator is not thread-safe, a question how to increment an integer in a thread-safe manner? becomes valid. This time I will show you one of the ways. A method that is very simple to apply in almost any case.

 

What does thread-safe mean?

The increment Java operator (++) is not thread-safe. We already know that from one of the previous articles. But what does it really mean and why is that important?

An operation is thread-safe when it can be executed by multiple threads at the same time on the same object without breaking its consistency and still providing the correct result.
In Java we more often talk about objects that are thread-safe. A thread-safe object is an object that all its methods are thread-safe.

A classic example of a non-thread-safe object is an instance of StringBuilder. If you write a code that instantiates a StringBuilder, and then multiple threads append some texts to it using the StringBuilder.append method, the final content of the StringBuilder might be incorrect.
A thread-safe alternative to StringBuilder is StringBuffer. It is a little bit slower, but it uses synchronization to ensure internal consistency. Thanks to it, you can append texts using StringBuffer without worrying about multiple threads.

 

Thread-safe alternative to ++ operator

Incrementing an integer is such a basic operation that it would be unimaginable to not have a thread-safe alternative. The solution is AtomicInteger from java.util.concurrent.atomic package. To instantiate an object, you use the constructor new AtomicInteger(123) providing an integer as a parameter. Unfortunately, you cannot use basic operators like +, -, * for calculations. Instead, there are custom methods:
addAndGet, accumulateAndGet, getAndUpdate, updateAndGet and so on.

An alternative to i++ is the incrementAndGet method:

AtomicInteger i = new AtomicInteger(123);
i.incrementAndGet();

Do not miss valuable content. You will receive a monthly summary email. You can unsubscribe anytime.

incrementAndGet methods can be executed by multiple threads on the same instance of AtomicInteger without breaking the result. I wrote a simple unit test to demonstrate that.

package com.dbapresents.concurrencytest;

import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

import static org.junit.jupiter.api.Assertions.assertEquals;

class IncrementingTest {

private final AtomicInteger globalVariable = new AtomicInteger(0);

@Test
void shouldExecuteInParallel() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(10);
List<Callable<Void>> subTasks = List.of(
this::increment100times,
this::increment100times,
this::increment100times,
this::increment100times,
this::increment100times,
this::increment100times,
this::increment100times,
this::increment100times,
this::increment100times,
this::increment100times
);
executorService.invokeAll(subTasks);

assertEquals(1000, globalVariable.get());
}

private Void increment100times() {
for (int iter = 0; iter < 100; iter++) {
globalVariable.incrementAndGet();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}

}

It creates a pool of 10 threads using the ExecutorService. Then it submits 10 tasks for execution. Each task increments a single global AtomicInteger 100 times. As it is easy to calculate, the expected result is 10*100=1000 at the end.

Go ahead and run it. The test passes because the calculated number is exactly 1000, even though the incrementing was done in parallel by multiple threads.

If you do not want to trust me that a regular Integer would not work, replace AtomicInteger with Integer and see for yourself. Or check Is i++ atomic article.

If you like what I do, consider buying me a coffee :)

Buy me a coffeeBuy me a coffee