iamcrypticcoder
iamcrypticcoder

Reputation: 2899

Java Concurrency with Atomic Class

As I know operations on Atomic classes of Java concurrency API are executed one after one when trying to execute the same operation from multiple threads, the output of the following program seems inconsistent to me.

public class VisitorCounterAtomic {

    private AtomicInteger visitorCount = new AtomicInteger(0);

    public void visitAndPrint() {
        System.out.println("Total Visitors: " + visitorCount.incrementAndGet());
    }

    public static void main(String... args) {
        ExecutorService service = null;
        VisitorCounterAtomic counter = new VisitorCounterAtomic();

        try {
            service = Executors.newFixedThreadPool(20);
            for (int i = 0; i < 10; i++)
                service.submit(() -> counter.visitAndPrint());
        } finally {
            if (null != service) service.shutdown();
        }
    }
}

Output:

Total Visitors: 1
Total Visitors: 4
Total Visitors: 2
Total Visitors: 5
Total Visitors: 3
Total Visitors: 6
Total Visitors: 7
Total Visitors: 8
Total Visitors: 9
Total Visitors: 10

My expected output:

Total Visitors: 1
Total Visitors: 2
Total Visitors: 3
Total Visitors: 4
Total Visitors: 5
Total Visitors: 6
Total Visitors: 7
Total Visitors: 8
Total Visitors: 9
Total Visitors: 10

I know I could generate my expected output by using synchronization block, but I need an explanation why not using only atomic variable generate the expected output.

My reasoning is like - Regardless of the order of thread execution it will increment and print before another thread increments and prints the value of the atomic variable.

Upvotes: 4

Views: 925

Answers (2)

Naresh Bharadwaj
Naresh Bharadwaj

Reputation: 302

The AtomicInteger class provide the Atomic Operation. It means it will make sure that only one thread at a time do the operation on that variable. It is Non blocking in nature as well. Here in your code multiple threads are running at the same time so AtomicInteger is doing its Job Pretty well but which thread will complete its task first it is not depend on AtomicInteger.

To solve this problem, You can use Syncronized Function to solve this Problem.

Upvotes: -1

davidxxx
davidxxx

Reputation: 131546

The actual order doesn't have any relation with AtomicInteger.
AtomicInteger guarantees that the value may be updated atomically. It doesn't guarantee that the threads are sequentially executed.
Indeed the ExecutorService instance processes the tasks in an asynchronous way.
So you cannot have a predictable task completion order.
Actually you have a race condition between the execution of incrementAndGet()and println():

public void visitAndPrint() {        
    System.out.println("Total Visitors: " + visitorCount.incrementAndGet());
}

For example suppose :

  • thread A executes visitorCount.incrementAndGet() (counter = 1) but not println()
  • thread A is paused
  • thread B executes visitorCount.incrementAndGet() (counter = 2) and println()
  • Thread A is resumed. println() is executed

Result :

Total Visitors: 2

Total Visitors: 1

By synchronizing the method you should have the expected order :

public synchronized void visitAndPrint() {        
    System.out.println("Total Visitors: " + visitorCount.incrementAndGet());
}

Upvotes: 4

Related Questions