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 of the primitive type int
are already atomic but AtomicInteger
comes with many operations which are not atomic on int
.
The simplest is the getAndXXX
or xXXAndGet
. For instance getAndIncrement()
is an atomic equivalent to i++
which is not atomic because it is actually a shortcut for three operations: retrieval, addition, and assignation. compareAndSet
is very useful for implementing semaphores, locks, latches, etc.
Using the AtomicInteger
is faster and more readable than performing the same using synchronization.
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.
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));
}