我有一个正常的生产者/消费者模式。
它有1个生产者和N个消费者。
现在,我##标题##想要尝试同时生产然后消费,但仍使用1个生产者线程和N个消费者线程。
所以基本上它应该像Produce()-> consume(),produce()-> consume(),produce()-> consume()...
但是现在我有多个使用方线程,我希望它们在条件下处于await(),因此,如果在produce()-> consume()之后发生另一个consumer(),它将等待。
假设我有1个生产者和4个消费者,看起来可能像这样:
Produce()-> consume()-> consume()。await-> consume()。await()-> consume()。await()-> produce()-> ...
问题:生产者线程进入cond.await();之后,代码可以工作,但是我不了解。他怎么还能调用cond1.signalAll();?
顺序代码不应该在cond.await()处停止吗?
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Processor {
private Lock lock = new ReentrantLock();
private Condition cond = lock.newCondition();
private Condition cond1 = lock.newCondition();
private int Counter = 0;
public void produce() throws InterruptedException {
while(true) {
lock.lock();
try {
Counter++;
System.out.println("Increased by one");
Thread.sleep(1000);
cond.await();
cond1.signalAll();
} finally {
lock.unlock();
}
}
}
public void consume() throws InterruptedException{
while(true) {
lock.lock();
try {
while(Counter==0) {
cond1.await();
}
Counter--;
System.out.println("Decreased by one!");
Thread.sleep(1000);
cond.signalAll();
}
finally {
lock.unlock();
}
}
}
}
最佳答案
您的生产者/消费者设置可能会失败,我将讨论造成这种情况的原因,但最初将解释其工作原理。生产者确实调用cond1.signalAll的原因是您如何设置生产者消费者通信。 Counter字段是生产者调用cond1.signalAll方法的原因。在这种情况下,可能有一些方案。
让我们开始假设生产者先于任何消费者获得了锁。然后,生产者将增加计数器,并使用cond.await调用将其置于等待状态。这将导致生产者放弃其锁定,并允许消费者之一获得锁定。然后,获得锁的使用者将看到计数大于零,并开始递减计数器。然后它将调用cond.signalAll并导致生产者收回该锁。然后,使用者释放锁并尝试重新获得该锁。如果生产者重新获得了锁定,它将执行与上述相同的过程。如果相反,消费者获得了锁,它将注意到计数器为零,并通过调用cond1.await使其处于等待状态。在这种情况下,生产者最终将获得锁定。
另一种情况是,消费者在生产者获得锁之前先获得了锁。使用者将看到计数器为零,并使用cond1.await将其置于等待状态。然后它将放弃其锁,另一个线程将获得该锁。然后,生产者可以获得锁,并且能够递增计数器并将自身置于等待状态。消费者随后将获得锁,并能够在向生产者发送信号之前消耗计数器。
如果所有消费者在生产者获得锁定之前先获得锁定,会发生什么?在那种情况下,消费者将执行与上述相同的步骤。最终,生产者将获得锁定并增加计数器。请注意,在这种情况下,生产者将在发出信号通知消费者之前先等待。这将使您的生产者/消费者永远等待而不做任何工作。这是唯一会导致系统故障的情况。然后,建议您首先发出信号,表明已为消费者工作,然后再将生产者置于等待状态。请注意,这种情况只有在最初启动生产者/消费者线程时才会发生。您可以通过启动所有使用者线程并等待一段时间,然后再启动生产者来轻松重现这种情况。这将产生上述情况。这实际上是一个边界情况,您只需要考虑在内即可。