我试图了解生产者消费者问题。为了复制该问题,我编写了以下代码
package com.company;
import java.util.ArrayDeque;
import java.util.Queue;
public class ProducerConsumerProblem {
private static Queue<Integer> q = new ArrayDeque<>(5);
public static void main(String args[]) {
Producer p = new Producer();
Consumer c = new Consumer();
Thread t = new Thread( p );
Thread t1 = new Thread( c );
t.start();
t1.start();
}
public static class Producer implements Runnable {
@Override
public void run() {
while(true) {
if (q.size() == 5) {
continue;
}
System.out.println( "Adding to queue" );
q.add( 1 );
}
}
}
public static class Consumer implements Runnable {
@Override
public void run() {
while(true) {
if (q.size() == 0) {
continue;
}
System.out.println( "Removing from queue" );
q.remove();
}
}
}
}
我期望得到类似concurrent exception
的信息,但是当队列为空或队列已满时,代码将停止。我的问题是,为什么在队列为空或已满时代码会停止,因为我和消费者和生产者都处于无限循环中,即使它们同时执行了错误的读取,但在以后的某个时刻,它们也会进行良好的读取,而生产者或消费者都应该工作。请帮我解决这种情况
答案 0 :(得分:1)
这两个线程可能会看到不同的大小,因为您的代码不是线程安全的,并且添加和删除操作是在不同的线程上完成的。
在线程1上执行q.add( 1 );
时,不一定将更新后的数组写到内存(即RAM)上,它可能仍在CPU寄存器中,并且当这两个线程发生上下文切换时,您的更改也可能在第二个线程中消失了,并且看不到更新后的大小。如果使用同步,则在同步块结束时,同步块中的所有更改都将保留在RAM中,这样就不会再发生不良行为。
由于ArrayDeque
不是线程安全的,因此您需要外部同步以使代码线程安全或使用并发数据结构。