【java】生产者和消费者问题 详细解说

介绍

生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

关系

生产者:生产者:负责生产数据的模块(可能是方法﹐对象,线程﹐进程);
消费者∶负责处理数据的模块(可能是方法,对象,线程,进程);
缓冲区∶消费者不能直接使用生产者的数据,)他们之间有个“缓冲区
生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据
在这里插入图片描述

主要使用的方法

狂神说Java截图

代码

管程法

public class ProducerAndConsumer {
    public static void main(String[] args) {
        //创建货架对象
        GoodsShelf goodsShelf = new GoodsShelf();
        //生产者消费者都是对一个货架进行操作,所以传参数都一样
        Producer producer = new Producer(goodsShelf);
        Consumer consumer = new Consumer(goodsShelf);
        //开始
        new Thread(producer).start();
        new Thread(consumer).start();
    }

}

//商品
class Iphone{
    int number;
    public Iphone(int number){
        this.number = number;
    }
}

//货架
class GoodsShelf{
    //可以放10个商品的货架
    Iphone[] iphones = new Iphone[10];
    //显示货架商品数量
    int count = 0;
    //对象调用的wait()方法时一定要在同步块或者同步方法中调用,以确保代码段不会被多个线程调用。
    public synchronized void pushIphone(Iphone iphone){
        //如果货架数量等于货架的最大容量则停止生产
        if (count == iphones.length){
            try {
                System.out.println("=============货架已满============");
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //商品放入货架
        iphones[count] = iphone;
        //商品数量加1
        count++;
        //通知消费者可以消费了
        this.notifyAll();
    }
    public synchronized Iphone popIphone(){
        //没有商品了等待生产线生产
        if (count == 0){
            try {
                System.out.println("=============货架没有商品了============");
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //产品数量减1。注意:商品的下标等于商品数量减1,所以要先减
        count--;
        //通知生产者生产
        this.notifyAll();
        return iphones[count];
    }
}

//生产者
class Producer implements Runnable{
    private final GoodsShelf goodsShelf;
    public Producer(GoodsShelf goodsShelf){
        this.goodsShelf = goodsShelf;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                //睡眠0.01秒方便观察。睡眠不释放锁
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            goodsShelf.pushIphone(new Iphone(i));
            System.out.printf("生产了%3d号手机\r\n",i);
        }
    }
}
//消费者
class Consumer implements Runnable{
    private final GoodsShelf goodsShelf;
    public Consumer(GoodsShelf goodsShelf){
        this.goodsShelf = goodsShelf;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                //睡眠
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Iphone iphone = goodsShelf.popIphone();
            System.out.printf("消费了%3d号手机\r\n",iphone.number);
        }

    }
}

信号灯法

生产者消费者通过标志变量来控制生产和消费

public class ProducerAndConsumer2 {

    public static void main(String[] args) {
        IPhone iPhone = new IPhone();
        new PhoneConsumer(iPhone).start();
        new PhoneProducer(iPhone).start();
    }
}

//操作的对象
class IPhone{
    private int number;
    //标志变量
    boolean flag = true;

    public synchronized void makeAPhone(int number){
        if (!flag){
            try {
                //等待消费者消费
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.number = number;
        System.out.println("+生产了"+number+"号手机");
        //修改标志变量,并通知消费者消费
        this.flag = !this.flag;
        this.notifyAll();
    }

    public synchronized void sellAPhone(){
        if (flag){
            try {
                //等待生产者生产
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("-卖出了"+number+"号手机");
        //修改标志变量,并通知生产者生产
        this.flag = !this.flag;
        this.notifyAll();
    }
}
//生产者
class PhoneProducer extends Thread{

    IPhone iPhone;
    public PhoneProducer(IPhone iPhone){
        this.iPhone = iPhone;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            iPhone.makeAPhone(i);
        }
    }
}
//消费者
class PhoneConsumer extends Thread{
    IPhone iPhone;
    public PhoneConsumer(IPhone iPhone){
        this.iPhone = iPhone;
    }
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            iPhone.sellAPhone();
        }
    }
}

参考:
【狂神说Java】
百度百科

每天进步一点点------------------------------------------------------------------
在这里插入图片描述在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值