在Java中使用锁的生产者和消费者
我从中得到了这个例子。但在那里,他们只是一个接一个地实现了这个例子。平均第一个要产生的整数,然后混淆,程序停止 以下是原始示例:在Java中使用锁的生产者和消费者,java,multithreading,Java,Multithreading,我从中得到了这个例子。但在那里,他们只是一个接一个地实现了这个例子。平均第一个要产生的整数,然后混淆,程序停止 以下是原始示例: class ProducerConsumerImpl { // producer consumer problem data private static final int CAPACITY = 10; private final Queue queue = new LinkedList<>(); private fina
class ProducerConsumerImpl {
// producer consumer problem data
private static final int CAPACITY = 10;
private final Queue queue = new LinkedList<>();
private final Random theRandom = new Random();
// lock and condition variables
private final Lock aLock = new ReentrantLock();
private final Condition bufferNotFull = aLock.newCondition();
private final Condition bufferNotEmpty = aLock.newCondition();
public void put() throws InterruptedException {
aLock.lock();
try {
while (queue.size() == CAPACITY) {
System.out.println(Thread.currentThread().getName()
+ " : Buffer is full, waiting");
bufferNotEmpty.await();
}
int number = theRandom.nextInt();
boolean isAdded = queue.offer(number);
if (isAdded) {
System.out.printf("%s added %d into queue %n", Thread
.currentThread().getName(), number);
// signal consumer thread that, buffer has element now
System.out.println(Thread.currentThread().getName()
+ " : Signalling that buffer is no more empty now");
bufferNotFull.signalAll();
}
} finally {
aLock.unlock();
}
}
public void get() throws InterruptedException {
aLock.lock();
try {
while (queue.size() == 0) {
System.out.println(Thread.currentThread().getName()
+ " : Buffer is empty, waiting");
bufferNotFull.await();
}
Integer value = queue.poll();
if (value != null) {
System.out.printf("%s consumed %d from queue %n", Thread
.currentThread().getName(), value);
// signal producer thread that, buffer may be empty now
System.out.println(Thread.currentThread().getName()
+ " : Signalling that buffer may be empty now");
bufferNotEmpty.signalAll();
}
} finally {
aLock.unlock();
}
}
}
已编辑
在考虑性能之后,我决定在signalall()之前的put
和get
方法中添加if条件代码>语句。(我认为它甚至可以提高0.000000左右的性能)但是中断wait();可能是一个死锁()代码>有什么帮助吗
对于生产者:
if(queue.size() == CAPACITY){
bufferNotFull.signalAll();
}
消费者:
if(queue.size() == 0){
bufferNotEmpty.signalAll();
}
修改后的代码就可以了
至于在不需要调用时跳过.singnalll()
调用可能的性能优化:仅当条件从false
更改为true
时才发出信号就足够了
对于制作人,您可以使用:
if(isAdded && queue.size() == 1) {
/*
* Element has been *actually added* *into empty queue*
* (previously .size() = 0), thus *queue become non-empty*.
*/
bufferNotFull.signalAll();
}
if(value && queue.size() == CAPACITY - 1) {
/*
* Element has been *actually consumed* *from full queue*
* (previousely .size() = CAPACITY), thus *queue become non full*.
*/
bufferNotEmpty.signalAll();
}
对于消费者,您可以使用:
if(isAdded && queue.size() == 1) {
/*
* Element has been *actually added* *into empty queue*
* (previously .size() = 0), thus *queue become non-empty*.
*/
bufferNotFull.signalAll();
}
if(value && queue.size() == CAPACITY - 1) {
/*
* Element has been *actually consumed* *from full queue*
* (previousely .size() = CAPACITY), thus *queue become non full*.
*/
bufferNotEmpty.signalAll();
}
注意,这种方式并不能消除对服务员不必要的通知(例如,消费者只能为空队列等待元素,因此只有添加第一个元素才会唤醒它)。相反,当明确知道没有线程等待它时,您消除了对.notifyAll()
的调用(例如,消费者不能在非空队列上等待)。根据您的程序的输出,在我看来,它正在做它应该做的事情:生产者将东西放入队列,消费者将它们取出。如果将while(true)
循环置于try
/finally
循环之外,可能会得到更多“混合”结果。然后,您可能会看到producer/producer/producer/consumer/consumer/consumer,而不是producer/producer/producer/consumer/consumer/consumer。正是由于Brian的评论,原始代码的行为比您的修改更自然。但原始代码对条件变量使用了混乱的命名:bufferNotFull
用于检查队列是否为空,而bufferNotEmpty
用于检查队列是否为空。请注意,在尝试减少信号发送时间时(在问题结束时),您使用变量名的自然意义:bufferNotFull
与queue.size()==CAPACITY
和bufferNotEmpty
与queue.size()==0
@Tsyvarev谢谢您的评论。好的,我明白了。没有concurreny/deadlock/hack/thread lock/thread safe问题吗?@BrianMalehorn谢谢,我刚刚决定先获得10个生产者,然后获得10个消费者,这就是为什么我使用while(true)inside try。那么concurreny/线程安全就没有问题了吗?@BrianMalehorn我将while循环放在try/finally之外,但它仍然生成相同的10乘10。。不是像你提到的那样一个接一个。在此处编码为什么使用queue.size()==1
?这将只通知一次。在这种情况下,没有解锁。我确信这可能会导致死锁。任何使用者只能在空状态(大小为0
)的队列中等待<每次队列从空状态(大小为0
)转换为非空状态(大小为1
)时,code>queue.size()==1
都会发出通知。这样我们就不会在需要的时候错过信号。我有点困惑,假设生产者会在队列中通知。size()==1
之后锁不会释放。。。所以制作人会再次制作。。然后大小将达到1。。那么,产品在尺寸达到1后如何通知消费者呢?无需就每一个元素添加通知消费者,单次通知就足够了。收到通知后,消费者将等待锁定
,直到生产者释放它(在元素插入完成系列之后)。然后使用者将发现队列不是空的,并将使用元素,直到队列再次变为空(queue.size()
变为0)。依此类推。消费者将自动开始消费并在不通知的情况下获得锁
-是。只有从返回时才需要通知。等待()
。从.lock()
(带锁)返回时不需要通知。