Java 中生产者消费者问题中使用原子整数的奇怪输出

Strange output using Atomic Integer in Producer Consumer Problem in Java

在 Java 中使用 BlockingQueue 实现生产者-消费者问题时,使用 AtomicInteger 得到奇怪的输出,其中 2 个线程产生相同的结果并将相同的计数器变量放入队列中。考虑到 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();
        }
    }

}

它产生如下输出,其中计数器达到 26

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

在不同的 运行 中也可以产生以下结果:其中计数器仅达到 25,这是正确的

no output

我知道我没有使用任何同步来更新计数器值并将其放入队列,这将解决序列输出的问题,但我关心的是了解原子整数的工作原理,以及它为什么不工作适合这种场景。 对这种行为的任何想法。谢谢

截至目前,您正在使用其 toString 方法打印 AtomicInteger

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

您需要提取 AtomicInteger

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

如果您之前没有提取它,在 toString 调用时该值可能已被另一个线程更新。它不再是 atomic