Java 生产者消费者模型的三种实现过程

2023-05-16

Java 生产者消费者模型的三种实现过程

生产者一边在生产,消费者一边消耗。当库存满的时候生产者暂停生产,直到有空位;当库存空的时候消费者暂停消费,直到有产品。
在这里插入图片描述

关键点:

  1. 生产者和消费者都是在不断生产和消费的,是同时并发的,不应该等满了再消费 / 空了再生产。
  2. 前提条件是生产速度和消费速度不同。

设计方法:

  1. 生产者和消费者分别使用一个线程模拟。将其抽象分别继承Runnable接口,生产和消费的行为放在Runnablerun()方法中.
  2. 控制生产和消费的速度不同。可以使每次生产 / 每次消费 之间的间隔不同,达到 生产比消费快 或者 消费比生产快 的效果.
  3. 生产者拿到仓库锁,判断是否还有空位:
    • 如果没有空位,就让自己先别再去试图抢占锁了(将自己放入等待池,wait());
    • 如果有空位,就生产一个,然后唤醒(notify())等待池中的线程(包括先前因为仓库空而wait()掉的线程)来竞争锁。
  4. 消费者拿到仓库锁,判断是否还有可以消费的商品:
    • 如果没有商品了,就让自己先别再去试图抢占锁了(将自己放入等待池,wait());
    • 如果有空位,就消费一个,然后唤醒(notify())等待池中的线程(包括先前因为仓库满而wait()掉的线程)来竞争锁。

1.使用synchronized 关键字

使用waitnotify实现

public class ProducerAndConsumerModel {
    public static void main(String[] args) {
        list = new ArrayList<>();
        //启动生产者消费者线程
        new Thread(new Producer()).start();
        new Thread(new Consumer()).start();
    }

    static int MAX_SIZE = 10;//定义仓库容量
    static List<Integer> list;//定义仓库

    //定义生产者
    private static class Producer implements Runnable{

        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(250);//生产效率:每250ms一个
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //第一步:获得锁
                synchronized(list){
                    //第二步:判断能不能生产
                    if(list.size() >= MAX_SIZE){
                        //进入此,代表库存已满,进入等待池,放弃锁,暂停线程
                        try {
                            list.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //能生产:生产一个
                    list.add(1);
                    System.out.println("生产了一个产品,现在有" + list.size() + "个产品");
                    //第三步:唤醒消费者线程,试图消费
                    list.notifyAll();
                }

            }
        }
    }

    //定义消费者
    private static class Consumer implements Runnable{

        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(500);//消费效率:每500ms消费一个
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //第一步:获得锁
                synchronized (list){
                    //第二步:判断能不能消费,即仓库是否为空
                    if(list.size() == 0){
                        try {
                            //如果发现没有商品:就进入等待池,释放锁,线程暂停
                            list.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //能消费:消费一个
                    list.remove(0);
                    System.out.println("消费了一个产品,现在还有" + list.size() + "个产品");
                    //唤醒生产者线程,试图生产
                    list.notifyAll();
                }
            }


        }

注意:我们在这里使用的notifyAll()这个方法,为什么不能用notify(),也就是随便叫醒一个消费者呢?

答案是不可以,使用 notify()是叫醒 LOCK 阻塞队列里面的任意一个线程,假如此时我们的临界区域已经满了,此时唤醒的是一个生产者线程,就会导致死锁,所以我们在这里采用的是notifyAll()这个方法,意思就是唤醒阻塞队列里面的全部线程,这样某一个消费者就可以去取出临界区里面的产品,从而避免死锁的发生。

2.使用ReenterantLock

ReenterantLocksynchronized类似,synchronized在语句块结束后会自动释放锁,ReenterantLock需要unlock()ReenterantLock还支持公平锁(等待最久的先拿锁)。

使用awaitsingalAll实现

public class ProducerAndConsumerModelReentrantLock {
    public static void main(String[] args) {
        list = new ArrayList<>();
        ableToProducer = lock.newCondition();
        ableToConsumer = lock.newCondition();

        new Thread(new Producer()).start();
        new Thread(new Consumer()).start();
    }
    static int MAX_SIZE = 10;
    static List<Integer> list;
    static ReentrantLock lock = new ReentrantLock(true);//指定为公平锁
    static Condition ableToProducer,ableToConsumer;


    //生产者
    private static class Producer implements Runnable{

        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(250);//250ms生产一个
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //第一步:获得锁
                lock.lock();
               try {
                   //第二步:判断能不能生产
                   if(list.size() >= MAX_SIZE){
                       try {
                           //进入此,代表库存已满,进入等待池,放弃锁,暂停线程
                           ableToProducer.await();
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
                   //能生产:生产一个
                   list.add(1);
                   System.out.println("生产了一个产品,现在有" + list.size() + "个产品");
                   //第三步:给消费者线程一个信号
                   ableToConsumer.signalAll();
               }finally {
                   lock.unlock();
               }
            }
        }
    }

    //消费者
    private static class Consumer implements Runnable{

        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(500);//每500ms消费一个
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //第一步:获得锁
                lock.lock();
                try{
                    //第二步:判断能不能消费,即仓库是否为空
                    if(list.size() == 0){
                        //如果发现没有商品:就进入等待池,释放锁,线程暂停
                        try {
                            ableToConsumer.await();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //能消费:消费一个
                    list.remove(0);
                    System.out.println("消费了一个产品,现在还有" + list.size() + "个产品");
                    //给生产者一个信号
                    ableToProducer.signalAll();
                }finally {
                    lock.unlock();
                }
            }
        }
    }
}

synchronized 相比之下,一个 lock 我们可以生成多个condition,换句话说synchronized就像是只有一个 conditionReentrantLock,所以 后者比前者更加的灵活,可以进行选择性的通知,但是也较为麻烦,因为每次都得手动地关闭锁,所以我们每次得尝试在finally 里面关闭锁。

3. 使用BlockingQueue

阻塞队列本身就是当队满的时候阻塞线程,故直接使用就可以实现生产者/消费者模型。
阻塞队列内部也是使用ReenterantLock实现的。

public class ProducerAndConsumerModelUseBlockingQueue {
    public static void main(String[] args) {
        queue =new ArrayBlockingQueue<Integer>(MAX_SIZE);
        new Thread(new Producer()).start();
        new Thread(new Consumer()).start();
    }

    static BlockingQueue<Integer> queue;//定义一个队列
    static int MAX_SIZE = 10;//定义最大容量

    //生产者
    private static class Producer implements Runnable{

        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(250);//250ms生产一个
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    //生产一个
                    queue.put(1);
                    System.out.println("生产了一个产品,现在有"+queue.size()+"个产品。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    //消费者
    private static class Consumer implements Runnable{

        @Override
        public void run() {
            while(true) {
                try {
                    Thread.sleep(500);//每500ms消费一个
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    //消费一个
                    queue.take();
                    System.out.println("消费了一个产品,现在有"+queue.size()+"个产品。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 生产者消费者模型的三种实现过程 的相关文章

  • 操作系统:Win10的沙盒是什么,如何使用,看完你就懂了

    Win10操作系统新增的windows沙盒是一种安全机制 xff0c 为执行中的程式提供的隔离环境 通常是作为一些来源不可信 具有破坏力或无法判定程序意图的应用程序提供实验之用 很多网友想要通过沙盒运行一些未知的程序 xff0c 但是不知道
  • 收集一些程序员励志经典名言

    1 作为一个真正的程序员 xff0c 首先应该尊重编程 xff0c 热爱你所写下的程序 xff0c 他是你的伙伴 xff0c 而不是工具 2 程序员可以让步 xff0c 却不可以退缩 xff0c 可以羞涩 xff0c 却不可以软弱 xff0
  • 夸克浏览器网页版入口网址分享

    夸克浏览器是一款简约 无广告的浏览器软件 xff0c 致力于带给用户最流畅舒适的使用体验 但是有用户问小编夸克浏览器的网页版入口地址在哪 xff1f 那么小编这里就给大家分享一下夸克浏览器网页版入口 夸克浏览器网页版入口地址分享 夸克浏览器
  • 由于找不到iutils.dll无法继续执行代码?

    电脑缺少某个dll文件是非常常见的系统错误 xff0c 但是如果遇到由于找不到iutils dll无法继续执行代码的问题 xff0c 那就不是简单的缺少文件问题了 xff0c 是中了流氓软件的问题 方法一 xff1a 1 这个问题是由于中了
  • excel制作表格的详细步骤

    excel是办公软件Microsoft office的组件之一 xff0c 很多用户都会使用excel来制作表格 xff0c 快捷方便 xff0c 但是还有不少用户不清楚怎么使用excel制作表格 xff1f 下面就一起来瞧瞧吧 xff01
  • ms-gamingoverlay一直跳出来怎么解决?

    最近有Win11玩家发现自己在玩游戏的时候经常弹出ms gamingoverlay的弹窗 xff0c 非常影响自己的游戏体验感 xff0c 那有什么办法可以解决这一问题吗 xff1f 大家可以按照以下的解决办法操作 xff0c 希望可以帮到
  • 联想电脑黑屏但电源键亮着的解决办法

    最近有联想电脑用户跟小编反应 xff0c 自己的笔记本屏幕黑屏了但是电源键还是亮着的 xff0c 这是怎么回事 xff1f 很多用户遇到这种情况往往不知所措 xff0c 不知道如何处理 xff0c 那么小编这里就给大家分享一下联想电脑黑屏电
  • 【XR】VR手柄设计之LED光点布局

    1 如何设计一台VR手柄 xff08 设计一台VR手柄需要考虑以下几个方面 xff1a xff09 功能 xff1a VR手柄需要具备一定的交互功能 xff0c 例如触摸板 按键 扳机等 xff0c 以及能够感知手部动作和姿态的传感器 舒适
  • Win11怎么彻底卸载Xbox Game Bar?

    Xbox Game Bar是常用于捕捉 记录屏幕并与其他游戏玩家朋友聊天的工具 xff0c 缺点就是运行过程中会占用大量的空间 xff0c 有什么办法可以卸载Xbox Game Bar xff0c 释放空间吗 xff1f 下面就来看看详细的
  • Win11打开本地组策略编辑器的两种方法

    Win11是新推出的操作系统 xff0c 但是用户对很多操作都不熟悉 xff0c 想要通过本地组策略编辑器修改一些配置 xff0c 都找不到本地组策略编辑器 xff0c 那么Win11怎么打开本地组策略编辑器呢 xff1f 一起来看看具体的
  • 介绍一下115sha1链接使用方法

    收到一个115 开头的网盘链接 xff0c 要如何下载呢 xff1f 单纯复制这个链接是没有办法直接下载的 xff0c 复制进去还会显示链接地址错误 xff0c 那么小编这里就给大家分享一下正确的使用方法 xff0c 希望可以帮到你 115
  • 夸克网盘的文件怎么保存到百度网盘?

    我们经常将自己的文件 视频等等都传到网盘上储存 xff0c 大大减少电脑和手机的占用 xff0c 其中百度网盘和夸克网盘是非常受欢迎的两款软件 xff0c 拥有超大的云储存空间 xff0c 用户想存什么就存什么 那夸克网盘的文件能存到百度网
  • Furmark如何进行正确的烤机?

    Furmark是一款非常不错的显卡性能以及稳定度测试软件 xff0c 通过这款软件可以快速测试出显卡的性能以及显卡是否稳定 xff0c 下面小编就来教教大家Furmark如何进行正确的烤机吧 1 打开Furmark xff0c 可以看到如图
  • WinRAR一直自动关闭怎么回事

    很多用户都习惯使用WinRAR来压缩解压文件 xff0c 但是有小伙伴跟小编反映自己的WinRAR老是一直闪退 xff0c 这是怎么回事 xff1f 下面就来看看WinRAR软件闪退的解决办法吧 Win10纯净版 Win10 64位纯净版
  • win11共享文件夹需要用户名和密码?

    在共享文件夹时提示需要用户名和密码 xff0c 这是怎么回事 xff1f 不少win11用户跟小编反映了这个问题 xff0c 我们要如何解决呢 xff1f 下面就来看看具体的win11共享文件夹需要用户名和密码的解决办法吧 win11共享文
  • win11桌面文件在哪个文件夹?

    很多win10系统用户应该都知道 xff0c 桌面文件默认存储在C xff1a Users Username Desktop文件夹中 xff0c 那升级win11之后 xff0c 桌面文件在哪个文件夹呢 xff1f 有没有改动呢 xff1f
  • win7时间总是不对怎么办?

    一般用户的主机中的主板会有一个电池 xff0c 这个电池可以给主板供电 xff0c 但是主板电池没电了的话就会将原本的时间设置清空 xff0c 因此这个时候时间就是不对的 xff0c 下面就是关于win7时间总是不对的解决方法 xff0c
  • Win10无法连接打印机怎么办?不能使用打印机的解决方法

    在我们平常的办公中 xff0c 经常会需要使用到打印机打印文件 想要使用打印机是需要先将电脑与打印机连接的 xff0c 但是有部分Win10用户遇到了无法连接打印机的情况 xff0c 对于这种情况应该如何解决呢 xff1f 下面来看看详细的
  • 【python】6DOF analyse tool

    1 result show 1 1 note 图1为3D位置 xff0c 图2 xff0c 3 xff0c 4分别表示yaw pitch xff0c roll角随着时间的变化的波动 2 code span class token comme
  • Spring入门预备知识(上)

    Spring入门主要使用了下面几个技术 xff1a 工厂模式 单例模式 动态代理模式 面向接口编程 xff0c 下面分几部分详细分析 一 xff09 工厂模式 1 定义 xff1a 定义一个用于创建对象的接口 xff0c 让子类决定实例化哪

随机推荐

  • 电脑丢失dll文件能一键修复吗,哪种修复方法靠谱?

    Dll文件的丢失其实是一件挺常见的事情的 xff0c 最近就有网友问小编 xff0c 关于dll文件丢失的相关问题 xff0c 他问电脑丢失dll文件能一键修复吗 xff1f 这里小编告诉你 xff0c 有方法一键修复 xff0c 但是需要
  • vcruntime140_1.dll无法继续执行代码,怎么解决这种问题?

    经常使用电脑的人 xff0c 可能对于这个弹出框应该不陌生 xff0c vcruntime140 1 dll无法继续执行代码 xff0c 其实会出现这种情况 xff0c 主要是因为缺少一个动态链接库 DLL 文件导致的 这个文件是 Visu
  • 这可能是最简单又有效的自监督学习方法了

    文 王珣 64 知乎 本文已获作者授权 xff0c 禁止二次转载 从Kaiming的MoCo和Hinton组Chen Ting的SimCLR开始 xff0c 自监督学习 xff08 SSL xff09 成了计算机视觉的热潮显学 凡是大佬大组
  • idea 2022.1 创建maven卡死解决

    1 关闭项目 2 新建maven项目 创建成功
  • FFmpeg 命令常见操作

    1 转码 ffmpeg i source mp4 ss 20 t 10 c copy my mp4 ffmpeg ss 10 t 15 accurate seek i test mp4 c a copy c v copy tt mp4 i
  • FFprobe查看&统计视频信息

    1 查看音视频信息 1 1 查看基本信息 ffprobe span class token number 1280 span x720 h264 8mbps 30fps span class token punctuation span m
  • Linux 查看文件夹大小,磁盘剩余空间(du/df)

    1 简介 du查看目录大小 xff0c df查看磁盘使用情况 2 du disk usage xff08 1 xff09 基本功能 递归查看文件夹下所有文件的大小 xff08 2 xff09 常用参数 xff1a h human reada
  • Python matplotlib高级绘图详解

    1 前言 前面我们介绍了使用matplotlib简单的绘图方法 xff08 见 xff1a Python应用matplotlib绘图简介 xff09 但是想要完全控制你的图形 xff0c 以及更高级的用法 xff0c 就需要使用 pyplo
  • ffmpeg视频精准剪切

    1 导言 ffmepg剪切视频 xff0c 很方便 xff0c 但是也有很大缺陷 xff1a xff08 1 xff09 剪切时间点不精确 xff08 2 xff09 有时剪切的视频开头有黑屏 造成这些问题的原因是ffmpeg无法seek到
  • 【python】6DOF analyse tool2

    result show 1 1 note 图1为3D X Y Z combination位置 xff0c 图4 xff0c 5 xff0c 6分别表示yaw pitch xff0c roll角随着时间的变化的波动 span class to
  • AudioChannelManipulation

    Manipulating audio channels with ffmpeg Contents stereo mono streamstereo 2 mono filesstereo 2 mono streamsmono stereo2
  • 音频节奏检测(Onset Detection)

    1 前言 最近市场上出现一些多个视频拼接而成MV xff0c 其原理是根据音频的节拍变换切换视频 我在这里讲述下如何进行音频节拍检测 2 音频检测一般流程 3 3 1 原始音频频谱 以1024为窗口 xff08 即每次读取1024个采样点
  • 金融时间序列分析:6. AR模型实例(R语言)

    0 目录 金融时间序列分析 xff1a 9 ARMA自回归移动平均模型 金融时间序列分析 xff1a 8 MA模型实例 xff08 Python xff09 金融时间序列分析 xff1a 7 MA滑动平均模型 金融时间序列分析 xff1a
  • 比特率,帧率,分辨率对视频画质的影响

    0 前言 前几天和别人讨论视频编码参数对视频清晰度影响 xff0c 今日查查文献在此记录总结下 对最终用户而言 xff0c 其只关心视频的文件大小和画面质量 其中画面质量包括 xff1a 分辨率 xff0c 清晰度和流畅度 流畅度 xff1
  • 搭建Android Camera项目工程

    0 前言 这块内容非常简单 xff0c 需要注意的有两个 xff1a 需要申请相机权限需要一个Surface用来预览 1 申请相机权限 1 1 申请Camera权限 span class hljs tag lt span class hlj
  • 获取webshell权限的45种方法

    1 到GoogLe 搜索一些关键字 edit asp 韩国肉鸡为多 多数为MSSQL数据库 2 到Google site cq cn inurl asp 3 利用挖掘鸡和一个ASP木马 文件名是login asp 路径组是 manage 关
  • EGLContext: eglMakeCurrent详解

    1 前言 在完成EGL的初始化之后 xff0c 需要通过eglMakeCurrent 函数来将当前的上下文切换 xff0c 这样opengl的函数才能启动作用 boolean eglMakeCurrent EGLDisplay displa
  • 关于root安装中出现的问题

    最近重装了系统fedora16 xff0c 重新安装了root xff0c 结果遇到了各种问题 xff0c 先是编译不通过 xff0c 在网上查了说是需要打个补丁 xff0c 那就打个补丁吧 xff0c 安装成功之后又出现了新的错误 Cou
  • fragment切换出现空白页

    近期遇到一个bug xff0c 找了好久的原因 xff0c 最后终于找到 xff0c 在此记录一下 app的大体框架是由tab 43 fragment来组成的 xff0c 就是类似于app 的底部有五个按钮 xff0c 没点击一个按钮就会切
  • Java 生产者消费者模型的三种实现过程

    Java 生产者消费者模型的三种实现过程 生产者一边在生产 xff0c 消费者一边消耗 当库存满的时候生产者暂停生产 xff0c 直到有空位 xff1b 当库存空的时候消费者暂停消费 xff0c 直到有产品 关键点 xff1a 生产者和消费