java多线程 一个生产者和多个消费者

2023-05-16

生产者和消费者模式是面试时很容易被问到的一类题,在平常的开发中也经常碰到,比如在网游开发中:用一个线程把收到的字节数据封装起来写到一个队列中,然后用一个或多个线程从该队列中把数据读取出来再分发。本文来实现类似的情景: 5个通宵加班并饿了一天的程序员去包子店吃小笼包,小笼包分为菜包和肉包,随机分配的,由于公司只给报销20个包子的钱,所以就只点了20个包子,包子店的老板娘一次只能蒸10个包子,而且是必须等他们吃完了蒸好的10个包子之后再继续做剩下的10个包子,由于这个世界本身是不公平的,所以抢的快的的就多吃点,但为了避免他们把包子抢烂,规定每次只能一个人去拿包子
这里生产者就是做包子的,消费者就是这5个饿晕了的coder,下面来看看怎么用代码实现它。
1. 创建包子店BreadShop.java,首先创建一些公用的数据
// 装包子的盘子
private ArrayList<Bread> breadList = new ArrayList<Bread>();
// 包子的种类:肉包和菜包
private BreadType breadTypes[] = { BreadType.MEAT, BreadType.VEGETABLES };
// 已经出炉的包子总数
private int totalCount = 0;
// 点的包子数
private final int MAX_COUNT = 20;
 
enum BreadType {
    MEAT, VEGETABLES
}
 
// 包子
class Bread {
    public BreadType type;
 
    public Bread(BreadType type) {
        this.type = type;
    }
}
2. 首先来了解一下代码中用到的几个方法:wait()、sleep()、notify()、notifyAll()
wait()和notify()以及notifyAll()是Object的方法,这三个方法跟锁有密切关系,必须写在synchronized代码块中。obj.wait()表示线程会释放对象obj的锁,处于等待状态,直到有其他线程调用obj对象的notify()或者notifyAll()函数,才有机会重新去竞争obj对象的锁。notify()和notifyAll()的区别:前者是唤醒等待池中的一个线程,然后系统会让它获得obj对象的锁;后者是唤醒所有等待该对象的线程,然后让它们去竞争obj对象的锁。虽然使用notify()或者notifyAll()都可以,但大多数情况下还是notifyAll()安全些,notify()可能由于一些代码缺陷出现死锁,特别是在一个生产者和多个消费者的模式中。
sleep()是Thread的函数,它指定线程休眠一段时间,但是不会释放对象的锁。
下面来实现生产者
class Product implements Runnable {
    private boolean isWork = false;
 
    public Product()
    {
        this.isWork = true;
    }
 
    // 把包子蒸熟后放到盘子里
    public void makeBread(Bread bread) {
        breadList.add(bread);
        switch(bread.type)
        {
        case MEAT:
            System.out.println("make a meat bread");
            break;
 
        case VEGETABLES:
            System.out.println("make a vegetables bread");
            break;
        }
    }
 
    @Override
    public void run() {
        while(isWork)
        {
            try {
                synchronized(breadList)
                {
                    // 他们还没吃完,继续等待
                    if(breadList.size() > 0)
                        breadList.wait();
                    // 一次蒸10个包子
                    for(int i = 0; i < 10; ++ i)
                    {
                        int type = new Random().nextInt(2);
                        Bread bread = new Bread(breadTypes[type]);
                        this.makeBread(bread);
                    }
                    totalCount += 10;
                    // 通知他们可以吃包子了
                    breadList.notifyAll();
                }
                // 做完了20个包子
                if(totalCount >= MAX_COUNT)
                {
                    isWork = false;
                }
            }catch(Exception e) {
                e.printStackTrace();
                isWork = false;
            }
        }
 
    }
}

盘子里如果有包子,老板娘则等他们吃完;如果盘子里没有包子,则立即做10个包子,蒸熟后通知那5个coder来拿包子,直到做完20个包子。
3. 实现消费者
class Consumer implements Runnable
{
 
    private int id;
    public Consumer(int id)
    {
        this.id = id;
    }
    // 吃包子
    public void eat(Bread bread)
    {
        BreadType type = bread.type;
        switch(type)
        {
        case MEAT:
            System.out.println("AlexZhou " + id + " eat a meat bread");
            break;
 
        case VEGETABLES:
            System.out.println("AlexZhou " + id + " eat a vegetables bread");
            break;
        }
    }
    @Override
    public void run() {
        while(true)
        {
            try{
                synchronized(breadList)
                {
                    // 包子还没做好
                    if(breadList.size() == 0)
                    {
                        // 吃完了所有包子
                        if(totalCount >= MAX_COUNT)
                            break;
                        // 通知老板娘赶快做包子
                        breadList.notifyAll();
                        // 等老板娘做包子
                        breadList.wait();
                    }
                    else
                    {
                        // 从盘子里拿包子吃
                        Bread bread = breadList.remove(0);
                        this.eat(bread);
 
                    }
                }
                // 这里模拟吃包子的时间,也可以增大其他线程获得锁的概率,提高公平性
                Thread.sleep(100);
 
            }catch(Exception e)
            {
                e.printStackTrace();
                break;
            }
        }
 
    }
}

盘子里如果有包子就去拿包子,拿到后就跑到角落里去吃,吃完后继续去拿;盘子里如果没有包子就叫老板娘继续做包子,直到吃完20个。
4. 现在来模拟这个情景
public static void main(String[] args) {
    BreadShop bs = new BreadShop();
    // 5个coder来到包子店点包子
    for(int i = 0; i < 5; ++ i)
    {
        Thread t = new Thread(bs.new Consumer(i));
        t.start();
    }
    // 老板娘开始做包子 
    Thread productThread = new Thread(bs.new Product());
    productThread.setPriority(Thread.MAX_PRIORITY);
    productThread.start();
}

打印的结果如下:
make a meat bread
make a vegetables bread
make a vegetables bread
make a vegetables bread
make a meat bread
make a vegetables bread
make a meat bread
make a meat bread
make a meat bread
make a vegetables bread
AlexZhou 1 eat a meat bread
AlexZhou 3 eat a vegetables bread
AlexZhou 2 eat a vegetables bread
AlexZhou 0 eat a vegetables bread
AlexZhou 4 eat a meat bread
AlexZhou 3 eat a vegetables bread
AlexZhou 1 eat a meat bread
AlexZhou 2 eat a meat bread
AlexZhou 0 eat a meat bread
AlexZhou 4 eat a vegetables bread
make a meat bread
make a meat bread
make a vegetables bread
make a meat bread
make a meat bread
make a vegetables bread
make a meat bread
make a meat bread
make a meat bread
make a meat bread
AlexZhou 1 eat a meat bread
AlexZhou 2 eat a meat bread
AlexZhou 4 eat a vegetables bread
AlexZhou 1 eat a meat bread
AlexZhou 2 eat a meat bread
AlexZhou 3 eat a vegetables bread
AlexZhou 0 eat a meat bread
AlexZhou 4 eat a meat bread
AlexZhou 2 eat a meat bread

AlexZhou 1 eat a meat bread


转载请注明来自:Alex Zhou的程序世界,本文链接:http://codingnow.cn/java/1053.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java多线程 一个生产者和多个消费者 的相关文章

  • STM32F4XX 采集编码器的溢出处理

    STM32F4XX定时器16位 xff0c 采集编码器时候会在0xFFFF溢出 xff08 假设配置period 61 0xFFFF xff09 假设不溢出的情况下1ms之内编码器变化的最大范围小于0x7FFF xff0c 则关于溢出则可以
  • dependencyManagement和dependencies的区别

    dependencyManagement和dependencies的区别 参考 xff1a http zhaoshijie iteye com blog 2094478 pom xml中build标签 cpf2016的博客 CSDN博客 还
  • VScode播放网易云音乐(详细讲解)

    步骤 安装插件 xff1a VSC Netease Music 按shift 43 ctrl 43 p xff0c 输入 nete 出现下图 在按shift 43 ctrl 43 p xff0c 输入 nete 即可选择播放音乐 xff08
  • 安装和配置openssl

    Steps to download compile and install are as follows Note Replace 0 9 8e with your version number Downloading OpenSSL Ru
  • 自定义异常的使用

    下面是定义一个自定义异常的例子 xff0c 开发中可以以此作为参考 xff0c 根据项目需求编写自己的异常类 package com thinkgem wlw modules job service 自定义异常要继承 Exception 类
  • Ant中的classpath配置和使用

    Ant手册中配置classpath采用classpath标签 xff0c 可是我发现这样配置总是不好用 xff0c 还是直接用path设置classpath 一 xff09 设置classpath的方法 lt path id 61 34 p
  • 在运行jar包中正确读取资源文件

    可能有不少初学者会有这样的困惑 xff1a 在你的代码里调用了一些资源文件 xff0c 如图片 xff0c 音乐等 xff0c 在调试环境或单独运行的时候可以正常显示或播放 xff0c 而一旦打包到jar文件中 xff0c 这些东东就再也出
  • Ant发布war包时,任务卡住不动也不报错

    使用ant给项目发布环境时 xff0c 任务卡住不动也不报错 xff0c 在网上查询了些资料 xff0c 估计是ant执行任务时虚拟机内存不够用 针对这个问题 xff0c 可以通过以下两种方法解决 xff1a 1 xff09 在javac节
  • Oracle函数:sys_connect_by_path

    Oracle函数 sys connect by path 主要用于树查询 层次查询 以及 多列转行 其语法一般为 xff1a select sys connect by path column name 39 connect symbol
  • JVM(Java虚拟机)中进程工作目录讲解

    每次我们用Java命令运行我们的Java程序 xff0c 都会在JVM中开启一个进程 xff0c 对于每一个进程 xff0c 都会有一个相对应的工作目录 xff0c 这个工作目录在虚拟机初始化的时候就已经设置好了 xff0c 默认的情况下
  • Java调用外部程序命令时线程阻塞问题分析

    文章参考 http www qqread com java 2010 05 w493489 html 今天要写个远程重启服务的功能 xff0c 为了开发速度 xff0c 暂时定为Java代码 43 WMIC命令的方法 xff0c 简单的说
  • 打造一台“苹果范儿”的 Linux 系统,桌面美化攻略来了~

    点击关注公众号 xff0c 实用技术文章及时了解 目录 前言参考文章1 安装工具gnome tweaks2 修改窗口的按钮位置3 安装gnome扩展并设置4 美化桌面主题5 美化图标6 美化光标7 美化桌面背景 xff0c 锁屏和登陆页面8
  • Android中的onConfigurationChanged方法没有被调用的原因

    在 Android中的onConfigurationChanged方法没有被调用的原因有很多 而刚入门是经常犯的两个错误直接导致onConfigurationChanged方法没有被调用 下面看看程序 package cn com impo
  • 31岁转行的我

    2011年从一所普通二本师范大学毕业后先后从事了两年的教育工作 xff0c 但都没有挣到钱 xff0c 12年从深圳回到西安 xff0c 参加了几次公务员和事业单位的招考 xff0c 几次因0 1分的微小差距与国家饭碗擦肩而过 后来决定不再
  • 吴军老师《给中学生/大学生的书单》----Yohao整理

    2018 7 27记录 span class hljs code 给中学生的书单 span 一 文学类 18本 span class hljs code 1 金庸和琼瑶各一本 长篇的比短篇的好 span span class hljs co
  • javaweb利用钉钉机器人向钉钉群推送消息(解决中文乱码)

    可以参考 官方文档 xff1a https open doc dingtalk com docs doc htm spm 61 a219a 7629140 0 0 karFPe amp treeId 61 257 amp articleId
  • HDFS命令

    HDFS命令 1 hdfs基本操作 HDFS命令有两种风格 xff1a hadoop fs开头的 hdfs dfs开头的 两种命令均可使用 xff0c 效果相同 1 1 常用命令 如何查看hdfs或hadoop子命令的帮助信息 xff0c
  • 【Http2特性——Binary framing layer--push---HPACK】

    google文档 Http2 http2 引入了不兼容的new binary framing layer 所以大版本号增加了除非使用tcp socket xff0c 否则看不出http的版本区别 指Http向上层暴露的API接口一致 xff
  • 【《架构整洁之道》 读书笔记1----从部署的角度看依赖翻转】

    前言 看 架构整洁之道 之前 xff0c 依赖翻转理解 xff1a 依赖于抽象 xff0c 而不是依赖于实现 抽象 xff1a 比如水果店Apple Banana xff0c 抽象个水果接口 IFruit xff0c 用 IFruit 接口
  • 【架构 Flutter实践 Clean架构 && TDD测试驱动开发---1.0】

    2022 11 12 补充 最近在开发中尝试用了clean架构 xff0c 感觉就是 麻烦 太多模板代码 xff0c 很容易过度开发 我认为了解这些理念是很重要的 xff0c 但应该跟随你的项目 流程 进行调整 裁剪 如果你们的流程是 服务

随机推荐

  • Flutter didUpdateWidget 的使用问题 ( 为什么不建议重写)

    简单总结 以我的认知 xff1a 不要重写 didUpdateWidget你需要重写 xff0c 是否是你设计有问题你确定要重写 xff0c 且设计没问题 评论下大佬 xff0c 我也学下这种case 总结 xff1a 不要依赖于 didU
  • java ClassLoader机制和如何加载外部class文件(含代码)

    Java类的生命周期 生命周期有 xff1a 加载 xff08 Loading xff09 验证 xff08 Verification xff09 准备 xff08 Preparation xff09 解析 xff08 Resolution
  • Android Studio开发Groovy

    Context xff1a 主要讲下Android Studio如何开发Groovy xff0c 搭环境这东西 xff0c 最恶心 我查了N多的外文 1 AS Android Studio 本身是支持Groovy的 xff0c Gradle
  • RXJava找不到AndroidSchedulers

    原因 xff1a 还需要依赖一个 RxAndroid xff0c RxAndroid里有AndroidSchedulers xff0c RxJava里是没有的 xff08 类似于Java的SDK不会包含 AndroidSDK里的TextVi
  • 安装APK 免输入vivo、oppo密码

    2020 06 03补充 最优化版本 GitHub demo地址 apk下载地址 新建一个APP xff0c 使用Accessibility功能 监听vivo的 安装引用 界面用户输入 vivo密码 xff0c 后续 自动填写用 安装应用弹
  • Android logct中的线程ID

    针对logcat中的线程ID 进程ID过滤 好奇的是 线程ID 并不是Thread类里的ID 64 Override protected void onCreate Bundle savedInstanceState super onCre
  • Java Socket 服务端发送数据 客户端接收数据

    服务端 xff1a package com thinkgem wlw modules api test socket 64 Author zhouhe 64 Date 2019 4 8 9 30 import java io import
  • 百度移动软件开发面试题(20131018)

    1 new与malloc的区别 xff1f 分析 xff1a 一 new和malloc都是用于申请动态内存 new使用delete释放空间 xff0c malloc使用free释放 new和delete是C 43 43 中的运算符 xff0
  • RK3568 Debian10 AP6275S Bluetooth调试

    overlay etc profile d start blutooth sh start blutooth sh chmod 777 sys class rfkill rfkill0 state echo 0 gt sys class r
  • Java与VBA通讯实践

    1 DDE 动态数据交换 方式 VBA具有DDE能力 xff0c Java没有 网上搜索了一下 xff0c 有几个公司开发了这方面的类库 xff0c 可以使Java具有DDE能力 xff08 1 xff09 JavaDDE nevaobje
  • Linux下如何设置程序的开机自启动功能

    文章目录 Linux下设置程序开机自启动1 etc rc local2 etc profile d 3 使用 crontab 方式4 使用 systemd 服务测试代码 Linux下设置程序开机自启动 在最后 xff0c 我放了我测试时候要
  • vnc连接不上,vnc连接不上是为什么?原因详解

    vnc连接不上的原因 xff0c 服务器作为网站建设的常用设备 xff0c 在服务器运行过程中起到举足轻重的作用 用户在选择服务器是常用的方式有服务器租用 虚拟主机租用以及服务器托管 xff0c 通过进行文件以及数据的下载 上传等实现网站的
  • window10安装vnc无法使用,window10安装vnc无法使用的原因和解决办法

    window10安装vnc无法使用的原因 xff0c 服务器作为网站建设的常用设备 xff0c 在服务器运行过程中起到举足轻重的作用 用户在选择服务器是常用的方式有服务器租用 虚拟主机租用以及服务器托管 xff0c 通过进行文件以及数据的下
  • 企业信息化技术架构展望

    企业用户慢慢的从前期选用一些同行业成功的项目案例来复制 xff0c 或者选用一些知名的咨询公司提出的行业内通用方案 xff0c 转型为自己主动认真思考什么是自己需求 xff0c 什么是真正适合自己的信息化之路 做为企业信息技术架构设计 xf
  • Errors were encountered while processing: google-chrome-stable

    转自 xff1a http omtlab com errors were encountered while processing google chrome stable Many people facing this issue whi
  • virtualbox 命令

    VBoxManage命令详解 xff08 一 xff09 本人对vboxmange命令按我个人的理解作了解释 xff0c 由于本人水平有限难免有错误的地方 xff0c 希望大家帮我指正 VBoxManage v version 显示virt
  • 基于Springboot的物业管理系统_代码

    下载地址 1 1 课题背景 目的及意义 1 1 1 课题背景 互联网 43 改变着我们的生活 xff0c 在传统的社区物业服务领域 xff0c 在服务业主 提升社区服务 质量方面 xff0c 如何与互联网融合 xff1f 顶级互联网技术团队
  • eclips运行generatorConfig.xml文件生成代码

    描述 xff1a 如何通过eclips工具来运行 generatorConfig xml 文件来自动生成代码并获取数据 xff08 类似于mybaits逆向生成 xff09 xff1f mybatis generator generate
  • Spring源码(4)Context篇之AbstractApplicationContext(下)

    上一篇 Spring源码 4 Context篇之AbstractApplicationContext xff08 上 xff09 讲解了Spring的AbstractApplicationContext类refresh 方法 xff0c 前
  • java多线程 一个生产者和多个消费者

    生产者和消费者模式是面试时很容易被问到的一类题 xff0c 在平常的开发中也经常碰到 xff0c 比如在网游开发中 xff1a 用一个线程把收到的字节数据封装起来写到一个队列中 xff0c 然后用一个或多个线程从该队列中把数据读取出来再分发