两个生产者和一个消费者的实现代码如下:
public class NotifyDemo { public static void main(String[] args) { FactoryByCondition factory = new FactoryByCondition(); // 生产者 Thread producer = new Thread(() -> { try { factory.put(); } catch (InterruptedException e) { e.printStackTrace(); } }, "生产者"); producer.start(); // 生产者 2 Thread producer2 = new Thread(() -> { try { factory.put(); } catch (InterruptedException e) { e.printStackTrace(); } }, "生产者2"); producer2.start(); // 消费者 Thread consumer = new Thread(() -> { try { factory.take(); } catch (InterruptedException e) { e.printStackTrace(); } }, "消费者"); consumer.start(); } }
程序的执行结果如下图所示:
从上述结果可以看出,当使用 Condition
时,生产者、消费者、生产者 2 会一直交替循环执行,执行结果符合我们的预期。
2.性能问题
在上面我们演示 notify
会造成线程的“假死”问题的时候,一定有朋友会想到,如果把 notify
换成 notifyAll
线程就不会“假死”了。
这样做法确实可以解决线程“假死”的问题,但同时会到来新的性能问题,空说无凭,直接上代码展示。
以下是使用 wait
和 notifyAll
改进后的代码:
/** * 工厂类,消费者和生产者通过调用工厂类实现生产/消费功能. */ class Factory { private int[] items = new int[1]; // 数据存储容器(为了演示方便,设置容量最多存储 1 个元素) private int size = 0; // 实际存储大小 /** * 生产方法 * @throws InterruptedException */ public synchronized void put() throws InterruptedException { // 循环生产数据 do { while (size == items.length) { // 注意不能是 if 判断 // 存储的容量已经满了,阻塞等待消费者消费之后唤醒 System.out.println(Thread.currentThread().getName() + " 进入阻塞"); this.wait(); System.out.println(Thread.currentThread().getName() + " 被唤醒"); } System.out.println(Thread.currentThread().getName() + " 开始工作"); items[0] = 1; // 为了方便演示,设置固定值 size++; System.out.println(Thread.currentThread().getName() + " 完成工作"); // 唤醒所有线程 this.notifyAll(); } while (true); } /** * 消费方法 * @throws InterruptedException */ public synchronized void take() throws InterruptedException { // 循环消费数据 do { while (size == 0) { // 生产者没有数据,阻塞等待 System.out.println(Thread.currentThread().getName() + " 进入阻塞(消费者)"); this.wait(); System.out.println(Thread.currentThread().getName() + " 被唤醒(消费者)"); } System.out.println("消费者工作~"); size--; // 唤醒所有线程 this.notifyAll(); } while (true); } }