生产者和消费者案例

1.案例描述

这里以吃饭为例,假设有一个桌子,用来存汉堡包,然后有厨师和消费者,厨师往桌子上放汉堡包,消费者从桌子上取走汉堡包。当两者在一个时间段同时进行多次自己的操作时,很明显这就是多线程编程的生产者消费者实例了。在这里,我们希望厨师每次生产一个汉堡包,消费者就拿走一个汉堡包,如果汉堡包还没有被取走,那么厨师应该等待,而如果桌子上没有汉堡包,则消费者应该等待。

2.案例分析

厨师类(Cooker):实现Runnable接口【通用】,包含放汉堡包的方法
消费者类(Foodie):实现Runnable接口【通用】,包含拿汉堡包的方法
桌子类(Desk):共享数据
生产者消费者线程套路:
//1. while(true)死循环
//2. synchronized锁,锁对象要唯一
//3.判断,共享数据是否结束.[true]结束
//4.判断,共享数据是否结束,[false]没有结束

测试类(Demo1):测试类按如下步骤实现这个案例
(1) 创建桌子对象作为共享数据区域
(2) 创建厨师线程,把桌子对象作为参数传递至构造方法【需创建对应的桌子对象成员变量】,因为厨师需要完成放汉堡包的操作
(3)创建消费者线程,把桌子对象作为对象传递至构造方法【需创建对应的桌子对象成员变量】,因为消费者需要完成拿汉堡包的操作
(4)启动线程

3.代码实现

<1>等待唤醒实现
wait(); :【等待】
notifyAll() :【叫醒等待的所有线程】

public class Demo1 {
    public static void main(String[] args) {
        Desk desk = new Desk();
        Foodie foodie = new Foodie(desk);
        foodie.start();
        Cooker cooker = new Cooker(desk);
        cooker.start();
    }
}

//厨师类
public class Cooker extends Thread {
    private Desk desk;
    public Cooker(Desk desk) {
        this.desk = desk;
    }
    @Override
    public void run() {
        //生产者步骤:
        while (true) {
            //同步代码块
            synchronized (desk.getLock()) {
                //判断汉堡包的数量是否达到
                if (desk.getCount() == 0) {
                    break;
                } else {
                    //1,判断桌子上是否有汉堡包
                    if (!desk.isFlag()) {
                        //3.如果没有才生产
                        System.out.println("生产者生产汉堡包");
                        // 把汉堡包放在桌上
                        desk.setFlag(true);
                        //叫醒等待的消费者开吃
                        desk.getLock().notifyAll();
                    } else {
                        //2.如果有就等待
                        try {
                            //使用什么对象当做锁,那么就必须用这个对象去调用等待和唤醒的方法
                            desk.getLock().wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

//消费者类
public class Foodie extends Thread {
    private Desk desk;
    public Foodie(Desk desk) {
        this.desk = desk;
    }
    //消费者步骤:
    @Override
    public void run() {
        while (true) {
            //同步代码块
            synchronized (desk.getLock()) {
                //判断汉堡包的数量
                if (desk.getCount() == 0) {
                    break;
                } else { //1,判断桌子上是否有汉堡包
                    if (desk.isFlag()) {
                        //3,如果有就开吃
                        System.out.println("吃货吃汉堡包");
                        //4,吃完之后,桌子上的汉堡包就没有了
                        //叫醒等待的生产者继续生产汉堡包的总数量减一
                        desk.setCount(desk.getCount() - 1);
                        desk.setFlag(false);
                        desk.getLock().notifyAll();//叫醒等待的所有线程[把生产者唤醒]
                    } else {
                        //2,如果没有就等待
                        //没有就等待[释放锁再等待]
                        //使用什么对象当做锁,那么就必须用这个对象去调用等待和唤醒的方法
                        try {
                            desk.getLock().wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

//桌子类
public class Desk {
    //定义一个标记
    //true表示有,false表示没有汉堡包
    //public static boolean flag;
    private boolean flag;
    //定义一个汉堡包数,表示消费几个结束
    //public static int count = 10;
    private  int count;
    //定义一个锁对象 用于消费者线程和生产者线程用同一把锁
    //public static final Object lock =new Object();
    private final Object lock =new Object();

    public Desk(boolean flag, int count) {
        this.flag = flag;
        this.count = count;
    }

    public Desk() {
        //无参构造可用于初始化赋值
        this(false,3);
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public Object getLock() {
        return lock;
    }
}

打印结果:
----------------------------------------------------------------------
生产者生产汉堡包
吃货吃汉堡包
生产者生产汉堡包
吃货吃汉堡包
生产者生产汉堡包
吃货吃汉堡包

<2>阻塞队列实现
创建阻塞队列实现对象,泛型为String[汉堡包],capacity[队列限量]–1[生产一个拿一个]
原理:阻塞队列的put和take方法内部有锁

//测试类
public class Demo1 {
    public static void main(String[] args) {
        //创建阻塞队列实现对象,泛型为String[汉堡包],capacity[队列限量]--1[生产一个拿一个]
        ArrayBlockingQueue<String> list = new ArrayBlockingQueue<String>(1);
        Cooker cooker = new Cooker(list);
        Foodie foodie = new Foodie(list);
        new Thread(cooker).start();
        new Thread(foodie).start();//由于阻塞队列的put和take方法内部有锁,
        // 而我们加上的打印语句不在锁内,所以打印出来不均匀
    }
}

//厨师类
public class Cooker extends Desk implements Runnable {
    private  ArrayBlockingQueue<String> list;

    public Cooker(ArrayBlockingQueue<String> list) {
        this.list =list;
    }

    @Override
    public void run() {
        while (true){
            //判断汉堡数
            if(Desk.count==0){
                break;
            }
            //队列没有则生产
            try {
                list.put("汉堡包");//添加元素,添加满了则等待
                System.out.println("生产者生产了一个汉堡包");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

//消费者类
public class Foodie extends Desk implements Runnable {
    private ArrayBlockingQueue<String> list;

    public Foodie(ArrayBlockingQueue<String> list) {
        this.list = list;
    }

    @Override
    public void run() {
        while (true) {
            //判断汉堡数
            if(Desk.count==0){
                break;
            }
            //队列有则取出
            try {
                String s = list.take();//取出元素,取完了则等待
                Desk.count--;
                System.out.println("消费者拿出了" + s);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

//桌子类
public class Desk {
    static int count =3;
}

打印结果:
----------------------------------------------------------------------
生产者生产了一个汉堡包
生产者生产了一个汉堡包
消费者拿出了汉堡包
消费者拿出了汉堡包
生产者生产了一个汉堡包
消费者拿出了汉堡包

注:【因为阻塞队列有锁,锁会强制线程获取最新共享数据,则不会出现共享数据问题】
【阻塞队列的锁在内部,我们加上的打印语句不在锁内,所以打印出来不均匀】

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陪雨岁岁年年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值