合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
# 使用notifyAll完善多线程下的生产者消费者模型 我们先看一下wait()的代码注释: ![](https://img.kancloud.cn/e1/70/e170e77650493fe9113387e016db294b_694x307.png) 使当前线程等待,直到另一个线程调用了这个对象的notify()或notifyAll()方法,换句话说,这个方法是执行了wait(0); 当前线程必须拥有该对象的监视器。线程释放此监视器的所有权,并等待另一个线程通过调用notify()或notifyAll()方法,让这个对象监视器上等待的线程被唤醒,然后线程等待,直到它可以重新获得监视器的所有权并恢复执行。 notify()是通知一个线程唤醒,而notifyAll()是会将wait()在同一个monitor的所有线程都会唤醒,而我们之前出现问题就是因为notify是随机的,那么我们现在使用notifyAll试一下: ```java /** * @program: ThreadDemo * @description: 优化多线程下的生产者消费者模型,避免多生产者-多消费者造成的程序假死 * @author: hs96.cn@Gmail.com * @create: 2020-09-07 */ public class ProduceConsumerVersion3 { private int i = 0; private final Object LOCK = new Object(); private volatile boolean isProduced = false; public void produce() { synchronized (LOCK) { if (isProduced) { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "->" + (++i)); LOCK.notifyAll(); isProduced = true; } } public void consume() { synchronized (LOCK) { if (!isProduced) { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "->" + i); LOCK.notifyAll(); isProduced = false; } } public static void main(String[] args) { ProduceConsumerVersion3 pc = new ProduceConsumerVersion3(); Stream.of("P1", "P2", "P3").forEach(n -> new Thread(new Runnable() { @Override public void run() { while (true) { pc.produce(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }, n).start()); Stream.of("C1", "C2", "C3", "C4").forEach(n -> new Thread(() -> { while (true) { pc.consume(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }, n).start()); } } ``` 运行效果如下: ![](https://img.kancloud.cn/ce/e5/cee5e08d64338cccf31c0d24ba0dc5bc_1106x331.png) 可以看到有连续生产2个的情况,那么是什么原因导致的呢? 其实仔细想一下,就是p3的生产完之后释放锁,然后p2抢到了,就继续生产了,那么怎么解决呢?让p2wait到p3生产的数据消费掉即可了,改进代码如下:‘ ```java /** * @program: ThreadDemo * @description: 优化多线程下的生产者消费者模型,避免多生产者-多消费者造成的程序假死 * @author: hs96.cn@Gmail.com * @create: 2020-09-07 */ public class ProduceConsumerVersion3 { private int i = 0; private final Object LOCK = new Object(); private volatile boolean isProduced = false; public void produce() { synchronized (LOCK) { while (isProduced) { try { //System.out.println(Thread.currentThread().getName()+"wait...."); LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "->" + (++i)); LOCK.notifyAll(); isProduced = true; } } public void consume() { synchronized (LOCK) { while (!isProduced) { try { //System.out.println(Thread.currentThread().getName()+"wait...."); LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + "->" + i); LOCK.notifyAll(); isProduced = false; } } public static void main(String[] args) { ProduceConsumerVersion3 pc = new ProduceConsumerVersion3(); Stream.of("P1", "P2", "P3").forEach(n -> new Thread(new Runnable() { @Override public void run() { while (true) { pc.produce(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }, n).start()); Stream.of("C1", "C2", "C3", "C4").forEach(n -> new Thread(() -> { while (true) { pc.consume(); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } }, n).start()); } } ``` 运行效果如下: ![](https://img.kancloud.cn/f2/08/f20867c1bc65bbe48ba6954bbc590b0e_1154x456.gif)