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

Java中生产者-消费者问题中使用原子整数的奇怪输出,java,multithreading,concurrency,atomicinteger,Java,Multithreading,Concurrency,Atomicinteger,在Java中使用BlockingQueue实现生产者-消费者问题时,使用AtomicInteger获得奇怪的输出,其中两个线程产生相同的结果并将相同的计数器变量放入队列。考虑到原子整数使用的比较和交换技术,该输出如何可能 import java.util.Scanner; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concu

在Java中使用BlockingQueue实现生产者-消费者问题时,使用AtomicInteger获得奇怪的输出,其中两个线程产生相同的结果并将相同的计数器变量放入队列。考虑到原子整数使用的比较和交换技术,该输出如何可能

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();
        }
    }

}
在不同的运行中也可以产生以下结果:计数器最多只能达到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
时,该值可能已被另一个线程更新。它将不再是原子的。

递减值代码将被注释掉,并且不会运行。我只是把它作为生产者消费者问题的一部分放在这里。这里我们只对第一部分感兴趣,其中生产者只是简单地生成数据并将其放入队列中。为了避免混淆,我删除了消费者代码。thanks@RohitNarang您将计数器变量传递给System.out.println,因此将调用其toString方法。根据编辑,这不再是一个原子操作了。@RohitNarang它应该仍然能正常工作,对吗?
计数器将仅为
7
once@RohitNarang哦,是的,这不是一个原子操作,队列使用它自己的ReentrantLock。@RohitNarang是的,在这种特定情况下,您需要增加队列容量,但它仍然可以是一个未定义的行为,因为它取决于每个线程的行为。通常,队列插入和移除仅由两个线程处理,以避免同步问题。
final int e = counter.incrementAndGet();
queue.put(e);
System.out.println("Producer has produced the data:" + Thread.currentThread().getName() + " : " + e);