生产者与消费者关系与阻塞队列

本文介绍了Java并发编程中的等待唤醒机制,通过厨师与顾客的生产者消费者模型展示了wait(), notify(), notifyAll()方法的使用。同时,将原始代码改造为更具面向对象特性的版本,并引入了阻塞队列的概念,演示了如何使用ArrayBlockingQueue实现等待唤醒机制,简化了生产者和消费者线程的交互过程。
摘要由CSDN通过智能技术生成

等待和唤醒的方法
        void wait() 导致当前线程等待,知道另一个线程调用该对象的notify()方法或nottifyAll()方法
        void notify()  唤醒正在等待对象监视器的单个线程
        void notifyAll()  唤醒正在等待对象监视器的所有线程    消费者和生产者 案例
        厨师与顾客之间的关系  厨师=》生产者  顾客=》消费者
    消费者步骤 
            1.判断桌子上是否有食物
            2.没有就等待
            3.有就执行
            4.执行完毕之后,桌上的食物就没有了,叫醒生产者生产,食物-1
    生产者步骤
            1.判断是否有食物,有就不用生产,没有就生产
            2.把食物生产出来
            3.叫醒消费者
    有一个生产者类,有一个消费者类,食物放置的地方,定义一个标记是否存在食物  还有一个测试类
    生产者类
    

public class Cooker extends Thread{
    @Override
    public void run() {
//        生产者步骤
//        1.判断是否有食物,有就不用生产,没有就生产
//        2.把食物生产出来
//        3.叫醒消费者
        while (true){
            synchronized (Desk.lock){
                if (Desk.count==0){
                    //只生产10份
                    break;
                }else{
                    if (!Desk.flag){
                        //没有食物
                        System.out.println("我做好饭了");
                        Desk.flag=true;
                        Desk.lock.notifyAll();
                    }else{
                        //有食物
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                }
            }
        }
    }
}


消费者类

public class Eat extends Thread{
    @Override
    public void run() {
//        消费者步骤
//        1.判断桌子上是否有食物
//        2.没有就等待
//        3.有就执行
//        4.执行完毕之后,桌上的食物就没有了,叫醒生产者生产,食物-1
        //并不知道自己执行多少次  while循环
        while (true){
            //需要定义同一把锁,不能定义在消费者类,也不能定义在生产者类,定义在Desk中  共享
            synchronized (Desk.lock){
                if (Desk.count==0){
                    break;
                }else {
                    if (Desk.flag){
                        //有
                        System.out.println("消费者正在执行");
                        //修改食物状态
                        Desk.flag=false;
                        //唤醒全部生产者
                        Desk.lock.notifyAll();
                        Desk.count--;
                    }else{
                        //没有就等待,使用什么对象当作锁,那么就必须用这个对象去调用等待和唤醒方法
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}


静态标记类 

public class Desk {
    //定义一个标记
    //如果为true  表示食物存在,不用创建食物,允许消费者消费
    //如果为false,表示食物不存在,需要厨师执行
    public static boolean flag=false;
    //食物的数量
    public  static  int count=10;
    //锁对象,生产者和消费者共享
    public  static  final  Object lock=new Object();

}

测试类为
public class Demo {
    public static void main(String[] args) {
//        消费者步骤
//        1.判断桌子上是否有食物
//        2.没有就等待
//        3.有就执行
//        4.执行完毕之后,桌上的食物就没有了,叫醒生产者生产,食物-1
//        生产者步骤
//        1.判断是否有食物,有就不用生产,没有就生产
//        2.把食物生产出来
//        3.叫醒消费者

        Eat eat=new Eat();
        Cooker ck=new Cooker();
        eat.start();
        ck.start();
    }
}

代码这样写  不是很有面向对象特点只是方便理解 需要改写具有面向对象
    生产者类:
        

public class Cooker extends Thread{
    private Desk  desk;

    public Cooker(Desk desk) {
        this.desk=desk;
    }

    @Override
    public void run() {
//        生产者步骤
//        1.判断是否有食物,有就不用生产,没有就生产
//        2.把食物生产出来
//        3.叫醒消费者


        while (true){
            synchronized (desk.getLock()){
                if (desk.getCount()==0){
                    //只生产10份
                    break;
                }else{
                    if (desk.isFlag()){
                        //没有食物
                        System.out.println("我做好饭了");
                        desk.setFlag(true);
                        desk.getLock().notifyAll();
                    }else{
                        //有食物
                        try {
                            desk.getLock().wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

消费者类:

public class Eat extends Thread{
    private Desk desk;
    public Eat(Desk desk) {
        this.desk=desk;
    }

    @Override
    public void run() {
//        消费者步骤
//        1.判断桌子上是否有食物
//        2.没有就等待
//        3.有就执行
//        4.执行完毕之后,桌上的食物就没有了,叫醒生产者生产,食物-1
        //并不知道自己执行多少次  while循环
        while (true){
            //需要定义同一把锁,不能定义在消费者类,也不能定义在生产者类,定义在Desk中  共享
            synchronized (desk.getLock()){
                if (desk.getCount()==0){
                    break;
                }else {
                    if (desk.isFlag()){
                        //有
                        System.out.println("消费者正在执行");
                        //修改食物状态
                        desk.setFlag(false);
                        //唤醒全部生产者
                        desk.getLock().notifyAll();
                        desk.setCount(desk.getCount()-1);
                    }else{
                        //没有就等待,使用什么对象当作锁,那么就必须用这个对象去调用等待和唤醒方法
                        try {
                            desk.getLock().wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}


一些静态标记类 

public class Desk {
    //定义一个标记
    //如果为true  表示食物存在,不用创建食物,允许消费者消费
    //如果为false,表示食物不存在,需要厨师执行
    //public static boolean flag=false;
    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() {
        this(false,10);
    }

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

    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;
    }

    @Override
    public String toString() {
        return "Desk{" +
                "flag=" + flag +
                ", count=" + count +
                ", lock=" + lock +
                '}';
    }
}


测试类:

public class Demo {
    public static void main(String[] args) {
//        消费者步骤
//        1.判断桌子上是否有食物
//        2.没有就等待
//        3.有就执行
//        4.执行完毕之后,桌上的食物就没有了,叫醒生产者生产,食物-1
//        生产者步骤
//        1.判断是否有食物,有就不用生产,没有就生产
//        2.把食物生产出来
//        3.叫醒消费者
        Desk desk=new Desk();

        Eat eat=new Eat(desk);
        Cooker ck=new Cooker(desk);
        eat.start();
        ck.start();
    }
}


阻塞队列
    阻塞队列实现等待唤醒机制
    定义一个put方法,定义一个take方法
    阻塞队列结构图
    
    
    
    
    
    BlockingQueue的核心方法:
            put(anObject)将参数放入队列,如果放不进去会阻塞
            take();取出第一个数据,取不到会阻塞
        常见的BlockingQueue:
            ArrayBlockingQueue:底层是数组,有界
            LinkedBlockingQueue:单层是链表,无界,但不是真正的无界,int的最大值是max
        常见实例:
            public class Demo {
            public static void main(String[] args) throws InterruptedException {
                //阻塞队列的基本用法
                //创建阻塞队列的对象,容量为1
                ArrayBlockingQueue<String> arrayBlockingQueue=new ArrayBlockingQueue<>(1);
                //存储元素
                arrayBlockingQueue.put("食物");
                //取元素  返回值为取出的元素
                String take = arrayBlockingQueue.take();
            }
        }
对消费者和生产者代码的简写
消费者代码:

public class eat extends Thread{
    private ArrayBlockingQueue<String> list;
    public eat(ArrayBlockingQueue<String> arrayBlockingQueue) {
        this.list=arrayBlockingQueue;
    }

 

    @Override
    public void run() {
        while (true) {
            try {
                String take = list.take();
                System.out.println("消费者队列消费了一份食物"+take);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


生产者:

public class cooker extends Thread{
    private ArrayBlockingQueue<String> list;
    public cooker(ArrayBlockingQueue<String> arrayBlockingQueue) {
    this.list=arrayBlockingQueue;
    }

    @Override
    public void run() {
        while (true) {
            try {
                list.put("食物");
                System.out.println("厨师在做了一份食物");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


测试类:

public class Demo {
    public static void main(String[] args) {
        //创建一个阻塞队列  容量为1
        ArrayBlockingQueue<String> arrayBlockingQueue=new ArrayBlockingQueue<>(1);
        //创建线程并开启
        cooker c=new cooker(arrayBlockingQueue);
        eat e=new eat(arrayBlockingQueue);
        c.start();
        e.start();
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值