Practical uses for AtomicInteger

JavaConcurrencyAtomic

Java Problem Overview


I sort of understand that AtomicInteger and other Atomic variables allow concurrent accesses. In what cases is this class typically used though?

Java Solutions


Solution 1 - Java

There are two main uses of AtomicInteger:

  • As an atomic counter (incrementAndGet(), etc) that can be used by many threads concurrently

  • As a primitive that supports compare-and-swap instruction (compareAndSet()) to implement non-blocking algorithms.

Here is an example of non-blocking random number generator from Brian Göetz's Java Concurrency In Practice:

    public class AtomicPseudoRandom extends PseudoRandom {
        private AtomicInteger seed;
        AtomicPseudoRandom(int seed) {
            this.seed = new AtomicInteger(seed);
        }

        public int nextInt(int n) {
            while (true) {
                int s = seed.get();
                int nextSeed = calculateNext(s);
                if (seed.compareAndSet(s, nextSeed)) {
                    int remainder = s % n;
                    return remainder > 0 ? remainder : remainder + n;
                }
            }
        }
        ...
    }

As you can see, it basically works almost the same way as incrementAndGet(), but performs arbitrary calculation (calculateNext()) instead of increment (and processes the result before return).

Solution 2 - Java

The absolute simplest example I can think of is to make incrementing an atomic operation.

With standard ints:

private volatile int counter;

public int getNextUniqueIndex() {
    return counter++; // Not atomic, multiple threads could get the same result
}

With AtomicInteger:

private AtomicInteger counter;

public int getNextUniqueIndex() {
    return counter.getAndIncrement();
}

The latter is a very simple way to perform simple mutations effects (especially counting, or unique-indexing), without having to resort to synchronizing all access.

More complex synchronization-free logic can be employed by using compareAndSet() as a type of optimistic locking - get the current value, compute result based on this, set this result iff value is still the input used to do the calculation, else start again - but the counting examples are very useful, and I'll often use AtomicIntegers for counting and VM-wide unique generators if there's any hint of multiple threads being involved, because they're so easy to work with I'd almost consider it premature optimisation to use plain ints.

While you can almost always achieve the same synchronization guarantees with ints and appropriate synchronized declarations, the beauty of AtomicInteger is that the thread-safety is built into the actual object itself, rather than you needing to worry about the possible interleavings, and monitors held, of every method that happens to access the int value. It's much harder to accidentally violate threadsafety when calling getAndIncrement() than when returning i++ and remembering (or not) to acquire the correct set of monitors beforehand.

Solution 3 - Java

If you look at the methods AtomicInteger has, you'll notice that they tend to correspond to common operations on ints. For instance:

static AtomicInteger i;

// Later, in a thread
int current = i.incrementAndGet();

is the thread-safe version of this:

static int i;

// Later, in a thread
int current = ++i;

The methods map like this:
++i is i.incrementAndGet()
i++ is i.getAndIncrement()
--i is i.decrementAndGet()
i-- is i.getAndDecrement()
i = x is i.set(x)
x = i is x = i.get()

There are other convenience methods as well, like compareAndSet or addAndGet

Solution 4 - Java

The primary use of AtomicInteger is when you are in a multithreaded context and you need to perform thread safe operations on an integer without using synchronized. The assignation and retrieval on the primitive type int are already atomic but AtomicInteger comes with many operations which are not atomic on int.

The simplest are the getAndXXX or xXXAndGet. For instance getAndIncrement() is an atomic equivalent to i++ which is not atomic because it is actually a short cut for three operations: retrieval, addition and assignation. compareAndSet is very useful to implements semaphores, locks, latches, etc.

Using the AtomicInteger is faster and more readable than performing the same using synchronization.

A simple test:

public synchronized int incrementNotAtomic() {
    return notAtomic++;
}

public void performTestNotAtomic() {
    final long start = System.currentTimeMillis();
    for (int i = 0 ; i < NUM ; i++) {
        incrementNotAtomic();
    }
    System.out.println("Not atomic: "+(System.currentTimeMillis() - start));
}

public void performTestAtomic() {
    final long start = System.currentTimeMillis();
    for (int i = 0 ; i < NUM ; i++) {
        atomic.getAndIncrement();
    }
    System.out.println("Atomic: "+(System.currentTimeMillis() - start));
}

On my PC with Java 1.6 the atomic test runs in 3 seconds while the synchronized one runs in about 5.5 seconds. The problem here is that the operation to synchronize (notAtomic++) is really short. So the cost of the synchronization is really important compared to the operation.

Beside atomicity AtomicInteger can be use as a mutable version of Integer for instance in Maps as values.

Solution 5 - Java

For example, I have a library that generates instances of some class. Each of these instances must have a unique integer ID, as these instances represent commands being sent to a server, and each command must have a unique ID. Since multiple threads are allowed to send commands concurrently, I use an AtomicInteger to generate those IDs. An alternative approach would be to use some sort of lock and a regular integer, but that's both slower and less elegant.

Solution 6 - Java

Like gabuzo said, sometimes I use AtomicIntegers when I want to pass an int by reference. It's a built-in class that has architecture-specific code, so it's easier and likely more optimized than any MutableInteger I could quickly code up. That said, it feels like an abuse of the class.

Solution 7 - Java

In Java 8 atomic classes have been extended with two interesting functions:

  • int getAndUpdate(IntUnaryOperator updateFunction)
  • int updateAndGet(IntUnaryOperator updateFunction)

Both are using the updateFunction to perform update of the atomic value. The difference is that the first one returns old value and the second one return the new value. The updateFunction may be implemented to do more complex "compare and set" operations than the standard one. For example it can check that atomic counter doesn't go below zero, normally it would require synchronization, and here the code is lock-free:

    public class Counter {

      private final AtomicInteger number;

      public Counter(int number) {
        this.number = new AtomicInteger(number);
      }

      /** @return true if still can decrease */
      public boolean dec() {
        // updateAndGet(fn) executed atomically:
        return number.updateAndGet(n -> (n > 0) ? n - 1 : n) > 0;
      }
    }

The code is taken from Java Atomic Example.

Solution 8 - Java

I usually use AtomicInteger when I need to give Ids to objects that can be accesed or created from multiple threads, and i usually use it as an static attribute on the class that i access in the constructor of the objects.

Solution 9 - Java

You can implement non-blocking locks using compareAndSwap (CAS) on atomic integers or longs. The "Tl2" Software Transactional Memory paper describes this:

> We associate a special versioned write-lock with every transacted > memory location. In its simplest form, the versioned write-lock is a > single word spinlock that uses a CAS operation to acquire the lock and > a store to release it. Since one only needs a single bit to indicate > that the lock is taken, we use the rest of the lock word to hold a > version number.

What it is describing is first read the atomic integer. Split this up into an ignored lock-bit and the version number. Attempt to CAS write it as the lock-bit cleared with the current version number to the lock-bit set and the next version number. Loop until you succeed and your are the thread which owns the lock. Unlock by setting the current version number with the lock-bit cleared. The paper describes using the version numbers in the locks to coordinate that threads have a consistent set of reads when they write.

This article describes that processors have hardware support for compare and swap operations making the very efficient. It also claims:

> non-blocking CAS-based counters using atomic variables have better > performance than lock-based counters in low to moderate contention

Solution 10 - Java

The key is that they allow concurrent access and modification safely. They're commonly used as counters in a multithreaded environment - before their introduction this had to be a user written class that wrapped up the various methods in synchronized blocks.

Solution 11 - Java

I used AtomicInteger to solve the Dining Philosopher's problem.

In my solution, AtomicInteger instances were used to represent the forks, there are two needed per philosopher. Each Philosopher is identified as an integer, 1 through 5. When a fork is used by a philosopher, the AtomicInteger holds the value of the philosopher, 1 through 5, otherwise the fork is not being used so the value of the AtomicInteger is -1.

The AtomicInteger then allows to check if a fork is free, value==-1, and set it to the owner of the fork if free, in one atomic operation. See code below.

AtomicInteger fork0 = neededForks[0];//neededForks is an array that holds the forks needed per Philosopher
AtomicInteger fork1 = neededForks[1];
while(true){    
    if (Hungry) {
        //if fork is free (==-1) then grab it by denoting who took it
        if (!fork0.compareAndSet(-1, p) || !fork1.compareAndSet(-1, p)) {
          //at least one fork was not succesfully grabbed, release both and try again later
            fork0.compareAndSet(p, -1);
            fork1.compareAndSet(p, -1);
            try {
                synchronized (lock) {//sleep and get notified later when a philosopher puts down one fork                    
                    lock.wait();//try again later, goes back up the loop
                }
            } catch (InterruptedException e) {}
    
        } else {
            //sucessfully grabbed both forks
            transition(fork_l_free_and_fork_r_free);
        }
    }
}

Because the compareAndSet method does not block, it should increase throughput, more work done. As you may know, the Dining Philosophers problem is used when controlled accessed to resources is needed, i.e. forks, are needed, like a process needs resources to continue doing work.

Solution 12 - Java

Simple example for compareAndSet() function:

import java.util.concurrent.atomic.AtomicInteger; 

public class GFG { 
    public static void main(String args[]) 
    { 

        // Initially value as 0 
        AtomicInteger val = new AtomicInteger(0); 

        // Prints the updated value 
        System.out.println("Previous value: "
                           + val); 

        // Checks if previous value was 0 
        // and then updates it 
        boolean res = val.compareAndSet(0, 6); 

        // Checks if the value was updated. 
        if (res) 
            System.out.println("The value was"
                               + " updated and it is "
                           + val); 
        else
            System.out.println("The value was "
                               + "not updated"); 
      } 
  } 

The printed is: previous value: 0 The value was updated and it is 6 Another simple example:

    import java.util.concurrent.atomic.AtomicInteger; 

public class GFG { 
    public static void main(String args[]) 
    { 

        // Initially value as 0 
        AtomicInteger val 
            = new AtomicInteger(0); 

        // Prints the updated value 
        System.out.println("Previous value: "
                           + val); 

         // Checks if previous value was 0 
        // and then updates it 
        boolean res = val.compareAndSet(10, 6); 

          // Checks if the value was updated. 
          if (res) 
            System.out.println("The value was"
                               + " updated and it is "
                               + val); 
        else
            System.out.println("The value was "
                               + "not updated"); 
    } 
} 

The printed is: Previous value: 0 The value was not updated

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJames P.View Question on Stackoverflow
Solution 1 - JavaaxtavtView Answer on Stackoverflow
Solution 2 - JavaAndrzej DoyleView Answer on Stackoverflow
Solution 3 - JavaPowerlordView Answer on Stackoverflow
Solution 4 - JavagabuzoView Answer on Stackoverflow
Solution 5 - JavaSergei TachenovView Answer on Stackoverflow
Solution 6 - JavaDavid EhrmannView Answer on Stackoverflow
Solution 7 - JavapwojnowskiView Answer on Stackoverflow
Solution 8 - JavaDguezTorresEmmanuelView Answer on Stackoverflow
Solution 9 - Javasimbo1905View Answer on Stackoverflow
Solution 10 - JavaMichael BerryView Answer on Stackoverflow
Solution 11 - JavaRodrigo GomezView Answer on Stackoverflow
Solution 12 - JavaM Shafaei NView Answer on Stackoverflow