网上有人说为什么要用两个condition来实现生产者消费者模式
public class ProducerConsumerPattern {
public static final int MAX_CAP = 1;
static LinkedList<Object> list = new LinkedList<>();
static ReentrantLock lock = new ReentrantLock();
static Condition notFull = lock.newCondition();
static Condition notEmpty = lock.newCondition();
static class Producer implements Runnable {
@Override
public void run() {
while (true) {
try {
lock.lock();
while (list.size() == MAX_CAP) {
try {
System.out.println("当前已有" + list.size() + "个产品,缓冲区已满,请等待消费者消费");
notFull.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(new Object());
System.out.println("生产了一个产品,当前产品个数为 " + list.size());
notFull.signal();
} finally {
lock.unlock();
}
}
}
}
static class Consumer implements Runnable {
@Override
public void run() {
while (true) {
try {
lock.lock();
while (list.size() == 0) {
try {
System.out.println("当前已有" + list.size() + "个产品,缓冲区已空,请等待生产者生产");
notFull.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.remove();
System.out.println("消费了一个产品,当前产品个数为 " + list.size());
notFull.signal();
} finally {
lock.unlock();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 3; i++) {
new Thread(new Producer()).start();
new Thread(new Consumer()).start();
}
如果只有一个condition,通过代码演示,程序卡着不动了。
image.png
设置队列容量为1,
假设现在队列为空,条件队列里有3个消费者线程等待被唤醒
image.png
生产者生产了一个产品之后调用signal通知消费者去消费,常规逻辑条件队列最后一个节点会转移到阻塞队列,之后就准备获取锁了。只要重新获取到锁了以后,继续往下执行。
image.png
在并发环境下,还没来得及操作最后节点,此时生产者线程抢到了锁,发现队列满了,会调用await方法被阻塞,进入条件队列尾部。
image.png
然后signal方法将生产者线程
移除到阻塞队列去竞争锁,因为没有消费者消费,竞争到锁后发现队列还是满的,就会一直阻塞在那
image.png
如果有两个condition,那么就会有两个条件队列。生产者阻塞会进入生产者条件队列等待被唤醒,消费者阻塞会进入消费者条件队列,隔离开来,互不影响,就不会出现上述情况。
网友评论