javamultithreadingconcurrencyatomicinteger

Strange output using Atomic Integer in Producer Consumer Problem in Java


While implementing Producer-Consumer Problem in Java using BlockingQueue, getting strange output using AtomicInteger, where 2 threads are producing the same result and putting the same counter variable in the queue. How are that output possible considering compare and swap technique used by Atomic Integer?

import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class ProducerConsumer {
    static BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(25);
    static AtomicInteger counter=new AtomicInteger(0);
    public static void main(String[] args) throws Exception{

        Runnable producer = () -> {
          while(!Thread.currentThread().isInterrupted()){
              try {
                  final int e = counter.incrementAndGet();
                  queue.put(e);
                  if(e==26){
                      System.out.println("this is breaking the sequence...., value 26");
                  }
                   // System.out.println("Producer has produced the data:" +e);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
        };

        ExecutorService producerPool = Executors.newFixedThreadPool(25);
        for(int i=0; i<10;i++){
            producerPool.submit(producer);
        }

        Thread.sleep(3000);
        Scanner scanInput= new Scanner(System.in);
        if(scanInput.next() != null){
            producerPool.shutdownNow();
        }
    }

}

it produces the output as below, where counter reached 26

this is breaking the sequence...., value 26

Can produce below result as well in different run : where counter reaches upto 25 only which is correct

no output

I know I am not using any synchronization for updating the counter value and put it in the queue, which will fix the issue with a sequence output, but my concern is understanding the Atomic Integer working, and how it is not suitable in this scenario. Any thoughts on this behavior. Thanks.


Solution

  • As of now you're printing the AtomicInteger value using its toString method

    "Producer has produced the data:" + Thread.currentThread().getName() + " : " + counter
    

    You need to extract the AtomicInteger value

    final int e = counter.incrementAndGet();
    queue.put(e);
    System.out.println("Producer has produced the data:" + Thread.currentThread().getName() + " : " + e);
    

    If you do no extract it before, at the time of the toString call the value could have been updated by another thread. It won't be atomic anymore.