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