What is AtomicInteger class and how is it different than using volatile or synchronized in a concurrent environment?

By | March 5, 2023

AtomicInteger is a class in Java that provides a way to perform atomic operations on an integer value in a concurrent environment. Atomic operations are operations that are performed in a single, indivisible step, without interference from other threads. Examples of atomic operations include incrementing a counter, setting a value, and getting a value.

AtomicInteger provides several methods for performing atomic operations on an integer value, including get, set, compareAndSet, incrementAndGet, and getAndIncrement. These methods are implemented using low-level hardware primitives, such as compare-and-swap and load-linked/store-conditional, to ensure that the operations are performed atomically.

Using AtomicInteger is different from using volatile or synchronized in a concurrent environment. volatile ensures that updates to a variable are visible to all threads, but it does not guarantee atomicity of operations. This means that if multiple threads attempt to update a volatile variable at the same time, there is a risk of race conditions and data corruption.

synchronized, on the other hand, provides both visibility and atomicity guarantees, but it can be slow and can lead to contention between threads.

AtomicInteger provides the benefits of both volatile and synchronized, without their drawbacks. Atomic operations are performed atomically and are visible to all threads, without the need for locking or synchronization. This makes AtomicInteger a good choice for high-performance, concurrent applications where multiple threads need to perform operations on a shared integer value.

Here’s an example of how to use AtomicInteger to increment a counter in a multi-threaded environment:

import java.util.concurrent.atomic.AtomicInteger;

public class MyCounter {
private AtomicInteger count = new AtomicInteger(0);

public int getCount() {
return count.get();
}

public void increment() {
count.incrementAndGet();
}
}

public class MyThread implements Runnable {
private MyCounter counter;

public MyThread(MyCounter counter) {
this.counter = counter;
}

public void run() {
for (int i = 0; i < 100000; i++) {
counter.increment();
}
}
}

public class Main {
public static void main(String[] args) throws InterruptedException {
MyCounter counter = new MyCounter();
Thread t1 = new Thread(new MyThread(counter));
Thread t2 = new Thread(new MyThread(counter));
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(“Counter value: ” + counter.getCount());
}
}

In this example, we define a MyCounter class that uses AtomicInteger to implement a thread-safe counter. We define a MyThread class that increments the counter 100,000 times, and we create two threads that each run an instance of the MyThread class. We wait for the threads to complete using the join() method, and then we print the final value of the counter. The output shows that the counter has been incremented atomically and is thread-safe.

Leave a Reply

Your email address will not be published. Required fields are marked *