多线程学习之生产者和消费者与阻塞队列的关系

news2024/12/27 12:54:49

生产者和消费者

概述:

生产者消费者问题,实际上主要是包含了两类线程:

  • 生产者线程用于生产数据
  • 消费者线程用于消费数据

生产者和消费者之间通常会采用一个共享的数据区域,这样就可以将生产者和消费者进行解耦,

两者都不需要互相关注对方的

方法:

Object类的等待和唤醒方法

方法名说明
void wait()导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法
void notify()唤醒正在等待对象监视器的单个线程
void notifyAll()唤醒正在等待对象监视器的所有线程

案例需求:

  • 桌子类(Desk):定义表示双吉芝士汉堡数量的变量,定义锁对象变量,定义标记桌子上有无双吉芝士汉堡的变量

  • 生产者类(Cooker):实现Runnable接口,重写run()方法,设置线程任务

    1.判断是否有双吉芝士汉堡,决定当前线程是否执行

    2.如果有双吉芝士汉堡,就进入等待状态,如果没有双吉芝士汉堡继续执行,生产双吉芝士汉堡

    3.生产双吉芝士汉堡之后,更新桌子上双吉芝士汉堡状态,唤醒消费者消费双吉芝士汉堡

  • 消费者类(Foodie):实现Runnable接口,重写run()方法,设置线程任务

    1.判断是否有双吉芝士汉堡,决定当前线程是否执行

    2.如果没有双吉芝士汉堡,就进入等待状态,如果有双吉芝士汉堡,就消费双吉芝士汉堡

    3.消费双吉芝士汉堡后,更新桌子上双吉芝士汉堡状态,唤醒生产者生产双吉芝士汉堡

  • 测试类(Demo):里面有main方法,main方法中的代码步骤如下

    创建生产者线程和消费者线程对象

    分别开启两个线程


/**
 * @Author:kkoneone11
 * @name:Cooker
 * @Date:2023/8/27 18:55
 */
public class Cooker extends Thread{
    private Desk desk;

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

//    生产者步骤:
//            1,判断桌子上是否有双吉芝士汉堡
//    如果有就等待,如果没有才生产。
//            2,把双吉芝士汉堡放在桌子上。
//            3,叫醒等待的消费者开吃。

    @Override
    public void run(){
        while(true){
            synchronized (desk.getLock()){
                if(desk.getCount() == 0){
                    break;
                }else {
                    if(!desk.isFlag()){
                        System.out.println("厨师正在制作双吉芝士汉堡");
                        //生产双层吉士
                        desk.setFlag(true);
                        //叫醒麦门弟子干饭
                        desk.getLock().notifyAll();
                    }else{
                        try{
                            desk.getLock().wait();
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}



public class Foodie extends Thread{
    private Desk desk;

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

//        1,判断桌子上是否有双吉芝士汉堡。
//        2,如果没有就等待。
//        3,如果有就开吃
//        4,吃完之后,桌子上的双吉芝士汉堡就没有了
//                叫醒等待的生产者继续生产
//        双吉芝士汉堡的总数量减一

    @Override
    public void run(){
        while(true){
            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 (Exception e){
                            e.printStackTrace();
                        }
                    }
                }

            }
        }
    }
}



public class Demo {
    public static void main(String[] args) {
        Desk desk = new Desk();

        Foodie f = new Foodie(desk);
        Cooker c = new Cooker(desk);

        f.start();
        c.start();
    }
}

阻塞队列:

阻塞队列继承结构:

常见BlockingQueue的实现类:

  • ArrayBlockingQueue: 底层是数组,有界
  • LinkedBlockingQueue: 底层是链表,无界.但不是真正的无界,最大为int的最大值

方法:

 实例:

public class Demo {
    public static void main(String[] args) throws Exception {
        // 创建阻塞队列的对象,容量为 1
        ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);

        // 存储元素
        arrayBlockingQueue.put("双层吉士");

        // 取元素
        System.out.println(arrayBlockingQueue.take());
        System.out.println(arrayBlockingQueue.take()); // 取不到会阻塞

        System.out.println("程序结束了");
    }
}

案例需求优化:

不再需要Desk这个类,改用阻塞队列

public class Cooker extends Thread{
    private ArrayBlockingQueue<String> bd;

    public Cooker(ArrayBlockingQueue<String> bd) {
        this.bd = bd;
    }
//    生产者步骤:
//            1,判断桌子上是否有汉堡包
//    如果有就等待,如果没有才生产。
//            2,把汉堡包放在桌子上。
//            3,叫醒等待的消费者开吃。

    @Override
    public void run() {
        while (true) {
            try {
                bd.put("汉堡包");
                System.out.println("厨师放入一个汉堡包");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


public class Foodie extends Thread{
    private ArrayBlockingQueue<String> bd;

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

    @Override
    public void run() {
//        1,判断桌子上是否有汉堡包。
//        2,如果没有就等待。
//        3,如果有就开吃
//        4,吃完之后,桌子上的汉堡包就没有了
//                叫醒等待的生产者继续生产
//        汉堡包的总数量减一
        while (true) {
            try {
                String take = bd.take();
                System.out.println("吃货将" + take + "拿出来吃了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

}


public class Demo {
    public static void main(String[] args) {
        ArrayBlockingQueue<String> bd = new ArrayBlockingQueue<>(1);

        Foodie f = new Foodie(bd);
        Cooker c = new Cooker(bd);

        f.start();
        c.start();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/939703.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1.MIMO信号检测

目录 最优信号检测算法 次最优信号检测算法 分层信号检测算法 线性信号检测算法 迫零线性信号检测算法 最小均方误差线性信号检测算法 非线性信号检测算法 在MIMO-OFDM系统中&#xff0c;信号检测算法可以通过将MIMO系统的信号检测算法应用于各个并行的子信道进行信号…

java八股文面试[JVM]——类初始化过程

回顾类加载过程&#xff1a; 知识来源&#xff1a; 【2023年面试】Class初始化过程是什么_哔哩哔哩_bilibili

哪种类型耳机不伤耳朵,对耳朵伤害最小的耳机类型

在骨传导耳机的普及浪潮下&#xff0c;人们越来越意识到长期使用传统耳机对耳道造成的伤害。许多朋友纷纷转向相对更加护听的骨传导耳机&#xff0c;但仍有一部分人对这项技术不太了解&#xff0c;甚至被误导认为骨传导耳机会对听力和大脑造成伤害。因此&#xff0c;我将给大家…

【应用层】网络基础 -- HTTPS协议

HTTPS 协议原理加密为什么要加密常见的加密方式对称加密非对称加密 数据摘要&&数据指纹 HTTPS 的工作过程探究方案1-只使用对称加密方案2-只使用非对称加密方案3-双方都使用非对称加密方案4-非对称加密对称加密中间人攻击-针对上面的场景 CA认证理解数据签名方案5-非对…

Redis限流实践:实现用户消息推送每天最多通知2次的功能

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…

log4net 输出中文乱码

如上图 在appender属性内加入 <param name"Encoding" value"utf-8" /> 问题解决!

区块链金融项目怎么做?

区块链技术的兴起引发了金融领域的变革&#xff0c;为金融行业带来了前所未有的机遇与挑战。在这个快速发展的领域中&#xff0c;如何在区块链金融领域做出卓越的表现&#xff1f;本文将从专业性和思考深度两个方面&#xff0c;探讨区块链金融的发展路径&#xff0c;并为读者提…

Crazyswarm无人机集群套件,为开发者提供一个实验、学习和开发的验证平台

无人机集群技术有着广泛的潜力应用&#xff0c;如搜索和救援、环境监测、农业、建筑、物流等。通过多个无人机的协同工作&#xff0c;可以提高效率、扩展覆盖范围以及执行一些单个无人机难以完成的任务。为实现室内环境无人机集群算法的验证以及更复杂的任务和应用&#xff0c;…

防静电地桩工程的流程和步骤

防静电地桩工程是在半导体生产厂房中非常重要的一项工程&#xff0c;它的目的是为了有效地消除或减少静电的积聚和释放&#xff0c;保护设备和产品。以下是进行防静电地桩工程的流程和步骤&#xff1a; 1. 规划与设计&#xff1a;首先需要根据厂房的布局、设备位置和业务需求来…

ES面试总结

前言 1、面试突击正确的学习姿势 老师在给你讲面试突击的时候&#xff0c;是有课件的&#xff0c;而且是有准备的。你在面试的时候&#xff0c;是没有笔记课件的&#xff0c;而且问题是由面试官提问的&#xff0c;具有一定的随机性面试突击课程的目标不是听懂&#xff0c;而是…

从原理到实战,手把手教你在项目中使用RabbitMQ

大家好呀&#xff0c;我是楼仔。 RabbitMQ 的文章之前写过&#xff0c;但是当时给的示例是 Demo 版的&#xff0c;这篇文章主要是结合之前写的理论知识&#xff0c;将 RabbitMQ 集成到技术派项目中。 不 BB&#xff0c;上文章目录&#xff1a; 下面我们先回顾一下理论知识&am…

【Hadoop】DataNode 详解

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的…

Python爬虫框架之快速抓取互联网数据详解

概要 Python爬虫框架是一个能够帮助我们快速抓取互联网数据的工具。在互联网时代&#xff0c;信息爆炸式增长&#xff0c;人们越来越需要一种快速获取信息的方式。而Python爬虫框架就能够帮助我们完成这个任务&#xff0c;它可以帮助我们快速地从互联网上抓取各种数据&#xf…

promethues监控postgres,emqx

1、安装监控 docker pull wrouesnel/postgres_exporter2、执行 docker run -d -p 9187:9187 --name postgres_exporter --nethost -d -e DATA_SOURCE_NAME"postgresql://postgres:123456192.168.12.116:5432/rcc-manage?sslmodedisable" wrouesnel/postgres_expor…

Java读(配置)文件 根目录下、s r c 和resources目录下的区别

1. 通过File类、InputStream读文件 在普通java项目中&#xff0c;当使用java io&#xff08;Fie类、FileInputStream类等&#xff09;读文件&#xff0c;传入相对路径时&#xff1a; 这种方式读文件&#xff0c;文件路径必须是项目的根路径&#xff0c;将文件放在其他任何目录…

皕杰报表(BIOS Report)中设置序号的方法之二

在皕杰报表如何设置序号系列之一里&#xff0c;我们用ds.#0来实现了序号&#xff0c;用ds.#0得到的数据库中选取的记录的序号。有些情况下&#xff0c;记录序号在报表中不是按照顺序显示的&#xff0c;而是在报表中又通过排序或分组后的结果显示的&#xff0c;例如&#xff1a;…

陪诊小程序|陪诊软件开发功能|陪诊平台优势

随着人们生活水平的提高&#xff0c;对健康的关注度也在不断增加。尤其是在疫情过后&#xff0c;人们对自己和家人的健康问题更加重视。因此陪诊系统应运而生&#xff0c;为用户提供便捷、高效的陪诊陪护和跑腿服务。那么陪诊系统包含哪些功能呢&#xff1f; 首先&#xff0c;陪…

2023年7月京东护发市场数据分析(京东数据产品)

如今&#xff0c;与面部护肤相比&#xff0c;多数消费者认为头皮也需要认真对待&#xff0c;这在年轻消费群体中体现的较为明显。 随着消费者对护发理念的认同感不断加深&#xff0c;人们日常居家洗护的步骤也更加精细、使用产品品类也愈加多样化。除传统的护发素、发膜等护发…

Dynamic ReLU:根据输入动态确定的ReLU

这是我最近才看到的一篇论文&#xff0c;它提出了动态ReLU (Dynamic ReLU, DY-ReLU)&#xff0c;可以将全局上下文编码为超函数&#xff0c;并相应地调整分段线性激活函数。与传统的ReLU相比&#xff0c;DY-ReLU的额外计算成本可以忽略不计&#xff0c;但表示能力明显增强&…

【数据结构】 队列(Queue)与队列的模拟实现

文章目录 &#x1f340;队列(Queue)的概念&#x1f38b;队列的使用&#x1f38d;队列的模拟实现&#x1f6a9;创建队列&#x1f6a9;入队列&#x1f6a9;出队列&#x1f6a9;获取队头元素&#x1f6a9;获取队列长度&#x1f6a9;判断是否为空&#x1f6a9;完整代码 &#x1f33…