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.
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.