1、概念
它描述的是有一块缓冲区作为仓库,生产者可以将生产好的产品放入仓库,消费者可以从仓库中取走产品并消费,仓库其实是一个临界资源,生产者和消费者其实就是线程,处理这个问题的核心:保证仓库中数据的安全性【线程之间的同步,在任意时刻都只有一个线程访问仓库】
2.实现
wait():当缓冲区已满或者为空时,生产者或者消费线程将停止自己的执行,放弃锁,使得自己处于等待状态,让其他的线程执行
·是Object的方法
·调用方式:对象.wait()
·表示释放锁标记,然后在锁外面进行等待【对比sleep,sleep是抱着锁休眠的】
·等待,必须放大同步代码块中执行
notify():当生产者或者消费者向缓冲区放入或者取走一个产品的时候,向其他等待的线程发出可执行的通知,同时释放锁,使得自己处于等待状态
·是Object的方法
·调用方式:对象.notify()
·表示 唤醒 锁 标记外面等待的线程,一次只能唤醒一个
notifyAll():全部唤醒
·是Object的方法
·调用方式:对象.notifyAll()
·表示 唤醒 锁 标记外面等待的所有的线程
总结:
线程之间的通信其实就是多个线程同时访问同一份资源的情况,但是操作的动作不懂,wait()、notify()、notifyAll()都是用在同步中,因为这三个方法都需要对锁进行操作
为什么这三个方法被定义在Object中,而不是Thread类中?
因为在这些方法在操作线程时,都必须要标记他们所操作线程持有的锁,为了数据的安全性,必须保证这三个方法锁操作的是同一把锁,而锁由于可以是任意的对象,所以可以被任意对象调用的方法定义在Object中
/* 一个生产线程,一个消费线程,程序运行没有问题 2个生产线程,2个消费线程,程序出现了生产一次消费两次,或生产两次消费一次的问题 出现问题的原因:线程被唤醒后没有判断标记,直接去生产或消费导致问题的发生 解决办法:线程被唤醒后先去判断标记,把if改成while 把if改成while后,又出现了死锁:原因是当线程唤醒的是本方线程时, 会导致所有线程进入等待状态,从而死锁 解决死锁:把notify()改成notifyAll(),问题解决了,但是不该被唤醒的 也被唤醒了,程序性能降低了 */ //描述产品 class Product { private String name; private int count=1; private boolean flag; public Product(){} //生产产品 public synchronized void produce(String name) { while(flag) { try{wait();}catch(InterruptedException e){e.printStackTrace();} } this.name=name+"..."+count; count++; System.out.println(Thread.currentThread().getName()+"...生产了..."+this.name); flag=true; notifyAll(); } //消费产品 public synchronized void consume() { while(!flag) { try{wait();}catch(InterruptedException e){e.printStackTrace();} } System.out.println(Thread.currentThread().getName()+"...消费了......"+this.name); flag=false; notifyAll(); } } //生产任务 class Producer implements Runnable { private Product product; public Producer(Product product) { this.product=product; } public void run() { while(true) { product.produce("笔记本"); } } } //消费任务 class Consumer implements Runnable { private Product product; public Consumer(Product product) { this.product=product; } public void run() { while(true) { product.consume(); } } } class Demo4 { public static void main(String[] args) { Product product = new Product(); //生产任务 Producer producer = new Producer(product); //消费任务 Consumer consumer = new Consumer(product); //生产线程 Thread t0=new Thread(producer); Thread t1=new Thread(producer); //消费线程 Thread t2=new Thread(consumer); Thread t3=new Thread(consumer); t0.start(); t1.start(); t2.start(); t3.start(); } }