Atomic operations

suggest change

An atomic operation is an operation that is executed “all at once”, without any chance of other threads observing or modifying state during the atomic operation’s execution.

Lets consider a BAD EXAMPLE.

private static int t = 0;

public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(400); // The high thread count is for demonstration purposes.
    for (int i = 0; i < 100; i++) {
        executorService.execute(() -> {
            t++;
            System.out.println(MessageFormat.format("t: {0}", t));
        });
    }
    executorService.shutdown();
}

In this case, there are two issues. The first issue is that the post increment operator is not atomic. It is comprised of multiple operations: get the value, add 1 to the value, set the value. That’s why if we run the example, it is likely that we won’t see t: 100 in the output - two threads may concurrently get the value, increment it, and set it: let’s say the value of t is 10, and two threads are incrementing t. Both threads will set the value of t to 11, since the second thread observes the value of t before the first thread had finished incrementing it.

The second issue is with how we are observing t. When we are printing the value of t, the value may have already been changed by a different thread after this thread’s increment operation.

To fix those issues, we’ll use the java.util.concurrent.atomic.AtomicInteger, which has many atomic operations for us to use.

private static AtomicInteger t = new AtomicInteger(0);

public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(400); // The high thread count is for demonstration purposes.
    for (int i = 0; i < 100; i++) {
        executorService.execute(() -> {
            int currentT = t.incrementAndGet();
            System.out.println(MessageFormat.format("t: {0}", currentT));
        });
    }
    executorService.shutdown();
}

The incrementAndGet method of AtomicInteger atomically increments and returns the new value, thus eliminating the previous race condition. Please note that in this example the lines will still be out of order because we make no effort to sequence the println calls and that this falls outside the scope of this example, since it would require synchronization and the goal of this example is to show how to use AtomicInteger to eliminate race conditions concerning state.

Feedback about page:

Feedback:
Optional: your email if you want me to get back to you:


Concurrent Programming Threads:
* Atomic operations

Table Of Contents
8 Arrays
10 Maps
11 Strings
16 Concurrent Programming Threads
25 JAXB
29 Enums
32 Audio
41 Scanner
63 Logging
75 Lists
78 Sets
89 JAX-WS
96 XJC
98 Process
106 Modules
114 Applets
122 JNDI
139 JavaBean
141 Literals
144 Packages
150 JMX
153 JShell
159 Sockets
167 Enum Map
175 Hashtable
177 SortedMap