线程间通信——生产者和消费者模式

  • Post author:
  • Post category:其他




消费者和生产者模式

是用来描述一个仓库(缓冲区),生产者可以将产品放入到仓库中,消费者可以从仓库中买走商品,解决生产者和消费者的生活逻辑问题,需要采用代码的同步机制来完成相互的【约束】和【提醒】。


注意事项

  1. 【商品是唯一共享资源】
  2. 消费者购买商品,清空商品的库存,要【提醒】生产者生产,并且消费者停止购买
  3. 生产者生产商品,填满商品的库存,要【提醒】消费者购买(到货通知),并且生产者是要停止生产操作

在这里插入图片描述



实现方法

采用wait()、notify()和notifyAll()方法。

wait():当缓冲区已满或空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行

  • 是Object的方法
  • 调用方式:对象.wait();
  • 表示释放 对象 这个锁标记,然后在锁外边等待(对比sleep(),sleep是抱着锁休眠的)
  • 等待,必须放到同步代码段中执行

notify():当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态

  • 是Object的方法
  • 调用方式:对象.notify();
  • 表示唤醒 对象 所标记外边在等待的一个线程,或者从多个待唤醒线程中随机唤醒一个

notifyAll():全部唤醒

  • 是Object的方法
  • 调用方式:对象.notifyAll()
  • 表示唤醒 对象 所标记外边等待的所有线程



案例

生产者生产面包,消费者消费面包,要求仓库有面包时,提醒消费者消费,生产者出于等待状态;当没有面包的时候,提醒生产者生产,消费者处于等待。即生产一件,消费一件。


基本思路:

  1. 创建面包类,构建相关的属性和方法。
  2. 创建面包仓库类,面包类对象传入,并创建sychronized修饰的同步方法——input和output方法。
  3. 创建两个线程,生产者product和消费者consumer,分别继承Runnable,重写run()方法,并分别调用input和output方法,保证同步。
  4. 在主方法创建Thread,并start。
/**
* 面包类
*/
public class Bread {
   
    private int id;
    private String productName;

    public Bread() {
   
    }
    public Bread(int id, String productName) {
   
        this.id = id;
        this.productName = productName;
    }

    public int getId() {
   
        return id;
    }
    public void setId(int id) {
   
        this.id = id;
    }
    public String getProductName() {
   
        return productName;
    }
    public void setProductName(String productName) {
   
        this.productName = productName;
    }
}

/**
* 面包容器类
*/
public class BreadCon {
   
    private Bread con;
    private boolean flag = false;   //判断仓库是否有面包,false表示没有

    public synchronized void input(Bread b) throws InterruptedException {
   
        if (flag) {
   
            this.wait();	//如果仓库有面包,则处于阻塞状态,等待消费者消费后唤醒
        }
        this.con = b;
        System.out.println(Thread.currentThread().getName() + "生产了" 
        + b.getId() + "号面包");
        flag = true;
        this.notify();	//仓库没有面包,则生产面包,并将标记改为true,唤醒消费者购买
    }

    public synchronized void output() throws InterruptedException {
   
        if (!flag) {
   
            this.wait();
        }
        Bread b= con;  
        con = null;
        System.out.println(Thread.currentThread().getName()+"消费了"
        +b.getId() + "号面包" +" 生产者:"+b.getProductName());
        flag = false;	//修改标记
        this.notify();	//唤醒生产者生产
    }
}

/**
* 生产者类
*/
public class Product implements Runnable{
   
    private BreadCon con;
    public Product(BreadCon con) {
   
        this.con = con;
    }
    @Override
    public void run() {
   
        for (i



版权声明:本文为qq_45337431原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。