Java 生产者和消费者(等待唤醒机制)

等待唤醒机制作用

简单来说,等待唤醒机制就是让多线程交替执行

生产者和消费者的理想情况

这里我们以厨师、吃货和桌子举例,吃货代表消费者用来消费数据,厨师代表生产者用来生产数据,利用桌子来控制线程的执行。所谓的理想情况就是厨师做一碗面条放到桌子上吃货来吃,又做了一碗吃货又去桌子上吃,以此交替执行。
在这里插入图片描述

生产者和消费者(消费者等待)

所谓消费者等待就是吃货先判断桌子上是否有食物,如果没有食物就等待,然后生产者制作食物,再把食物放到桌子上,最后唤醒等待的消费者来吃。
在这里插入图片描述

生产者和消费者(生产者等待)

生产者先判断桌子上是否有食物,如果有就等待,如果没有就去制作食物,然后把食物放到桌子上,最后叫醒消费者开吃。消费者也会先判断桌子上是否有食物,如果没有就等待,如果有就开吃,吃完之后,唤醒厨师继续做。
在这里插入图片描述

生产者和消费者常用方法

方法名称说明
void wait()当前线程等待,直到被其他线程唤醒
void notify()随机唤醒单个线程
void notifyAll()唤醒全部线程(常用)

代码演示:

生产者类(厨师)

package com.liming.waitandnotify;

/**
 * 生产者(厨师)
 */
public class Cook extends Thread{
    @Override
    public void run() {
        while (true){
            synchronized (Desk.lock){
                if (Desk.count == 0){
                    break;
                }else {
                    //1、判断桌子上是否有事物
                    if (Desk.foodFlag == 1){
                        //2、如果有就等待
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }else {
                        //3、如果没有,就制作面条
                        System.out.println("厨师做了一碗面条");
                        //4、修改桌子状态
                        Desk.foodFlag = 1;
                        //5、唤醒等待的消费者来吃
                        Desk.lock.notifyAll();
                    }
                }
            }
        }
    }
}

消费者类(吃货)

package com.liming.waitandnotify;

/**
 * 消费者(吃货)
 */
public class Foodie extends Thread{
    @Override
    public void run() {
        /*
        * 多线程的4步套路:
        *       1、循环
        *       2、同步代码块
        *       3、判断共享数据是否到了末尾(到了末尾)
        *       4、判断共享数据是否到了末尾(没有到末尾,执行核心逻辑)
        * */

        while (true){
            synchronized (Desk.lock){
                //到末尾了
                if (Desk.count == 0){
                    break;
                }else {
                    //没有到末尾执行核心逻辑
                    //1、先判断桌子上是否有面条
                    if (Desk.foodFlag == 0){
                        //2、没有,消费者等待
                        try {
                            Desk.lock.wait();//让当前线程跟锁进行绑定
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }else {
                        //3、把吃的总数-1
                        Desk.count--;
                        //4、如果有,开吃
                        System.out.println("吃货在吃面条还能再吃"+Desk.count+"碗");
                        //5、吃完之后唤醒厨师继续做
                        Desk.lock.notifyAll();
                        //6、修改桌子的状态
                        Desk.foodFlag = 0;
                    }
                }
            }
        }
    }
}

控制线程(桌子)

package com.liming.waitandnotify;

/**
 * 桌子
 */
public class Desk {
    /*
    * 作用:控制生产者和消费者的执行
    * */

    //是否有面条 0:有面条 1:没有面条
    public static int foodFlag = 0;

    //总个数,表示吃货最多吃10碗
    public static int count = 10;

    //锁对象
    public static Object lock = new Object();
}

测试类

package com.liming.waitandnotify;

public class TreadDemo {
    public static void main(String[] args) {
        /*
        * 需求:完成生产者和消费者(等待唤醒机制)的代码
        *       实现线程轮流交替执行的效果
        * */

        //创建线程对象
        Cook cook = new Cook();
        Foodie foodie = new Foodie();
        cook.setName("厨师");
        foodie.setName("吃货");
        cook.start();
        foodie.start();
    }
}

运行效果图:
在这里插入图片描述

等待唤醒机制(阻塞队列方式实现)

阻塞队列的继承结构

接口:Iterable➡Collection➡Queue➡BlockingQueue
实现类:ArrayBlockingQueue:底层是数组,有界
    LinkedBlockingQueue:底层是链表,无界,但不是真正的无界,最大为int的最大值

代码演示:
生产者类(厨师)

package com.liming.waitandnotify01;

import java.util.concurrent.ArrayBlockingQueue;

public class Cook extends Thread{
    ArrayBlockingQueue<String> queue;

    public Cook(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while (true){
            //不断的把面条放到阻塞队列中
            try {
                queue.put("面条");
                System.out.println("厨师放了一碗面条");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

消费者类(吃货)

package com.liming.waitandnotify01;

import java.util.concurrent.ArrayBlockingQueue;

public class Foodie extends Thread{
    ArrayBlockingQueue<String> queue;

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

    @Override
    public void run() {
        while (true){
            //不断从阻塞队列中获取面条
            try {
                String food = queue.take();
                System.out.println(food);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

测试类

package com.liming.waitandnotify01;

import java.util.concurrent.ArrayBlockingQueue;

public class ThreadDemo {
    public static void main(String[] args) {
        /*
        * 需求:利用阻塞队列完成生产者和消费者(等待唤醒机制)的代码
        * 细节:
        *       生产者和消费者必须使用同一个阻塞队列
        *       阻塞队列里面是有锁的不需要我们自己添加
        * */

        //1、创建阻塞队列对象
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);

        //2、创建线程的对象,并把阻塞队列传递上去
        Cook cook = new Cook(queue);
        Foodie foodie = new Foodie(queue);

        //3、开启线程
        cook.start();
        foodie.start();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小钟不想敲代码

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

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

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

打赏作者

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

抵扣说明:

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

余额充值