AtomicInteger class in Java
This post will look into the AtomicInteger class in Java, which can be used as an atomic integer counter in multi threaded environments that can be accessed by several threads concurrently.
We know that incrementing a counter is not a thread-safe operation in Java. To perform atomic operations on an integer counter, we have to synchronize every access-point to that counter, which will have a significant performance impact.
AtomicInteger class provides thread-safe operations on an integer counter that is accessed by different threads simultaneously, without using synchronization or heavily impacting the performance. AtomicInteger class has many utility methods which all are thread-safe, as shown below:
|
1 2 3 4 5 6 |
// initialize an `AtomicInteger` and int variable by 0 `AtomicInteger atomic = new AtomicInteger(0); int i = 0; int x = 10; int y; |
y = atomic.get();is equivalent toy = i;y = atomic.incrementAndGet();is equivalent toy = ++i;y = atomic.getAndIncrement();is equivalent toy = i++;y = atomic.decrementAndGet();is equivalent toy = --i;y = atomic.getAndDecrement();is equivalent toy = i--;y = atomic.addAndGet(x);is equivalent toi = i + x; y = i;y = atomic.getAndAdd(x);is equivalent toy = i; i = i + x;atomic.set(x);is equivalent toi = x;y = atomic.getAndSet(x);is equivalent toy = i; i = i + x;
UPDATE – Java 8 added many new functions to the AtomicInteger class, such as getAndUpdate(), updateAndGet(), getAndAccumulate(), accumulateAndGet() updates the current value with the results of applying the given function. For more details on these methods, check out Java documentation.
Here’s a Java program that demonstrates the working of the AtomicInteger class, where we have created three threads to update an AtomicInteger counter with the help of the getAndIncrement() method.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import java.util.concurrent.atomic.AtomicInteger; class AtomicIntegerExample implements Runnable { private static AtomicInteger atomic = new AtomicInteger(0); @Override public void run() { System.out.println(Thread.currentThread().getName() + "# " + atomic.getAndIncrement()); } } class Main { public static void main(String[] args) { AtomicIntegerExample target = new AtomicIntegerExample(); Thread t1 = new Thread(target); Thread t2 = new Thread(target); Thread t3 = new Thread(target); t1.start(); t2.start(); t3.start(); } } |
Output (may vary):
Thread-0# 1
Thread-2# 3
Thread-1# 2
Performance Test
Following is another simple Java program that measures the time taken to update an AtomicInteger, a synchronized int, and a simple int:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
import java.util.concurrent.atomic.AtomicInteger; class Main { private static AtomicInteger atomic = new AtomicInteger(0); private static int synchronizedCounter = 0; private static int counter = 0; public static void incrementAtomicCounter() { atomic.getAndIncrement(); } public static synchronized void incrementSynchronizedCounter() { synchronizedCounter++; } public static void incrementCounter() { counter++; } public static long benchmarkAtomicCounter() { long beg = System.nanoTime(); for (int i = 0; i < Integer.MAX_VALUE / 5; i++) { incrementAtomicCounter(); } return System.nanoTime() - beg; } public static long benchmarkNonAtomicCounter() { long beg = System.nanoTime(); for (int i = 0; i < Integer.MAX_VALUE / 5; i++) { incrementSynchronizedCounter(); } return System.nanoTime() - beg; } public static long benchmarkSimpleCounter() { long beg = System.nanoTime(); for (int i = 0; i < Integer.MAX_VALUE / 5; i++) { incrementCounter(); } return System.nanoTime() - beg; } public static void main(String[] args) { System.out.println("The time taken by AtomicInteger (in nanoseconds): " + benchmarkAtomicCounter()); System.out.println("The time taken by synchronized int (in nanoseconds): " + benchmarkNonAtomicCounter()); System.out.println("The time taken by int (in nanoseconds): " + benchmarkSimpleCounter()); } } |
Output (may vary):
The time taken by AtomicInteger (in nanoseconds): 2513303610
The time taken by synchronized int (in nanoseconds): 8465038962
The time taken by int (in nanoseconds): 26130822
Test Result: AtomicInteger performs better than a synchronized int.
Similar to AtomicInteger, java.util.concurrent.atomic package also provides the AtomicBoolean and AtomicLong class, representing a boolean and a long value that may be updated atomically, respectively.
That’s all about the AtomicInteger class in Java.
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)