Sharing primitives across threads in Java using atomic objects

Threading and parallel execution are popular choices when making applications more responsive and resource-efficient. Various tasks are carried out on separate threads where they either produce some result relevant to the main thread or just run in the background “unnoticed”. Often these tasks work autonomously meaning they have their own set of dependencies and variables. That is they do not interfere with a resource that is common to 2 or more threads.

However, that’s not always the case. Imagine that multiple threads are trying to update the same primitive like an integer counter. They perform some action and then update this counter. In this post we’ll see what can go wrong.

Here’s a service with methods to increment and decrement a counter. There’s also a method to get the current value of this counter:

The implementation of the call method is simple to follow. They increment or decrement the counter of the service the given number of times and then return the final result.

The following code will try to increment the counter 1,000,000 times and decrement it 400,000 times on two separate threads. Therefore we’re expecting the end result to be 600,000, right? Let’s see what happens:

We call the get method of the Future objects to make sure that the callables have completed. You should see that the end result “res” will be close to 600,000 but is not quite there. It can be 601,530 or 602,322. Occasionally the end result might even be exactly 600,000 if you get lucky.

The above problem is a classic resource sharing example in parallel computing. Two or more threads are trying to update the same primitive and some updates are lost. The problem is that increasing or decreasing an integer is not an atomic operation in Java – or in any other popular object-oriented language out there in fact. Adding an integer to another integer requires 3 instructions to the relevant section of the CPU: retrieve the current value of the variable, add the incoming value to it, assign the new value to the variable. With so many updates like in our example it is possible that a decrement and an increment operation produce these operations at the same time causing them to “intermingle”.

Luckily for us this is not a new problem and the Java Concurrency API has an easy solution to the problem. The java.util.concurrent.atomic package includes a number of objects whose names start with “Atomic” such as AtomicBoolean. They include AtomicInteger which is exactly what we need. The available methods, which are listed in the referenced documentation, will allow you to increment and decrement its value in an atomic way so that those basic instructions to the CPU will be shielded from other threads while they are being completed by a given thread.