所谓生产消费模型,是通过一个容器来解决生产者和消费者的强耦合问题。通俗的讲,就是生产者不断的生产,
消费之也在不断消费,消费者消费的产品是生产者生产的,这就必然存在一个中间的容器,我们可以把这个容器
想象成一个仓库,当仓库没有满的时候,生产者生产产品,当仓库满了的时候,生产者不能继续生产产品,而需
处于等待状态。当仓库不为空的时候,消费者可以消费产品,当仓库为空的时候,消费者不能再消费产品,而应
处于等待状态。这样不断循环,在这个过程中,生产者和消费者是不直接杰出的,所谓的仓库其实就是一个阻塞
队列,生产者生产的产品不直接提供给消费者,而是提供给阻塞队列,这个阻塞队列就是来解决生产者和消费者
之间的强耦合,这就是生产者消费者模型。
1、注意wait()是Object里面的方法,而不是Thread里面的。它的作用是将当前线程置于预执行队列,并在wait()
所在的代码处停止,等待唤醒通知。
2、wait()只能在同步代码块或同步方法中执行,如果调用wait()方法,而没有持有适当的锁,就会抛出异常。
wait()方法调用后会释放出锁,线程与其他线程竞争重新获取锁。
3、线程调用了wait()方法后一直在等待,不会继续往下执行,wait()一旦执行,除非接受到唤醒操作或者异常
中断,否则不会往下执行
1、notify()方法也是要在同步代码块或者同步方法中调用的,它的作用是使停止的线程继续执行,调用notify()
方法后,会通知那些等待当前线程对象锁的线程,并使它们重新获取该线程的对象锁,如果等待线程比较多的时候,
则由线程规划器随机挑选出一个呈现wait状态的线程。
2、notify()调用之后不会立即释放锁,而是当执行notify()的线程执行完成,即退出同步代码块或同步方法时,
才会释放对象锁。
唤醒所有处于等待状态的线程,一般使用notifyAll()比较多,因为notify随机唤醒一个线程,可能不是我们想要的
造成程序出现问题,notifyAll()唤醒所有等待线程则一定会得到我们想要的
Test类
package com.lding.test2; public class Test { public static void main(String[] args) { Queue queue=new Queue(); new Thread(new Producer(queue)).start(); new Thread(new Consumer(queue)).start(); } }
Queue类
package com.lding.test2; public class Queue { private int n; public int getN() { System.out.println("消费:"+n); return n; } public void setN(int n) { System.out.println("生产:"+n); this.n = n; } }
Producer类
package com.lding.test2; public class Producer implements Runnable{ Queue queue; Producer(Queue queue){ this.queue=queue; } @Override public void run() { int i=0; while (true){ queue.setN(i++); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
Consumer类
package com.lding.test2; public class Consumer implements Runnable{ Queue queue; Consumer(Queue queue){ this.queue=queue; } @Override public void run() { while (true){ queue.getN(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
运行结果
可以看到,0生产了一次却消费了两次。
Queue类
package com.lding.test2; public class Queue { private int n; public synchronized int getN() { System.out.println("消费:"+n); return n; } public synchronized void setN(int n) { System.out.println("生产:"+n); this.n = n; } }
生产了18并没有消费
生产了22消费了两次22
Queue类
package com.lding.test2; public class Queue { private int n; boolean flag=false;//flag=false 容器中无数据, flag=true 容器中有商品 public synchronized int getN() { if(!flag){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("消费:"+n); flag=false;//消费完毕 容器没数据 notifyAll(); return n; } public synchronized void setN(int n) { if(flag){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("生产:"+n); this.n = n; flag=true;//生产完毕 容器中有数据 notifyAll(); } }
运行结果完全是生产一个,消费一个,不会出现生产一次消费两次或者生产完不消费的情况。