生产者消费者模型-程序员宅基地

技术标签: java  开发语言  

一.生产者消费者模型的概念

生产者消费者模型多线程并发编程中的一种重要模式,用于解决生产者和消费者之间的协作问题。在这个模型中,生产者负责生成数据或者任务,然后将其交给消费者来处理,而消费者则负责处理这些数据或者任务

具体来说,生产者消费者模型通常涉及到一个共享的数据缓冲区(也称为队列),生产者向其中放入数据,而消费者从中取出数据进行处理。以下是该模型的基本概念:

  1. 生产者:负责生成数据或任务,并将其放入共享的数据缓冲区中。生产者的速度可能快于或者慢于消费者。

  2. 消费者:负责从共享的数据缓冲区中取出数据或任务,并进行处理。消费者可能以不同的速度处理数据,有些可能快速处理,有些可能慢速处理。

  3. 共享的数据缓冲区:生产者和消费者之间共享的数据存储区域。它可以是一个队列、缓冲区或者其他形式的数据结构。

  4. 协调机制:生产者和消费者之间需要一种机制来协调彼此的行为,例如当数据缓冲区为空时,消费者需要等待;当数据缓冲区满时,生产者需要等待。


二.生产者消费者模型的实现

1)阻塞队列

阻塞队列(Blocking Queue)是一种特殊类型的队列,它支持在队列为空时进行获取元素的线程阻塞等待,或者在队列已满时进行插入元素的线程阻塞等待。阻塞队列常用于生产者消费者模型中,可以帮助实现生产者和消费者之间的协调与同步。

代码实现:

public class BlockingQueue {

    //阻塞队列的长度
    private volatile int size;
    //存放数据的数组
    private int[] items=new int[1000];
    //队头
    private int head;
    //队尾
    private int tail;

    //put()方法放置生产者生产的元素
    public void put(int value) throws InterruptedException {
        //同一时间只能有一个线程放置,所以加锁
        synchronized (this){
            //如果队列满了,使当前线程等待,直到消费者消费元素后唤醒
            //建议为while而不是if, 否则 notifyAll 的时候, 该线程从 wait 中被唤醒
            //但是紧接着并未抢占到锁. 当锁被抢占的时候, 可能又已经队列满了
            //就只能继续等待
            while (size==items.length){
                wait();
            }
            //队列添加元素
            items[head]=value;
            head=(head+1)%items.length;
            size++;
            //添加后唤醒等待的线程
            notifyAll();
        }
    }

    //take()方法消耗消费者消费的元素
    public int take() throws InterruptedException {
        //用value存放要消耗的元素
        int value=0;
        synchronized (this){
            //如果队列为空,使当前线程等待,直到生产者消生产元素后唤醒
            while (size==0){
                wait();
            }
            //消耗元素
            value=items[tail];
            tail=(tail+1)%items.length;
            size--;
            //消费后唤醒等待的线程
            notifyAll();
        }
        return value;
    }
    
    //返回队列的长度
    public synchronized int size(){
        return size;
    }
}

2)模型实现

有了阻塞队列后,我们就可以简单的实现一个生产者消费者模型了

代码如下:

import java.util.Random;

public class Producer_Consumer {
    public static void main(String[] args) throws InterruptedException {
        //阻塞队列
        BlockingQueue blockingQueue=new BlockingQueue();

        //消费者线程
        Thread consumer=new Thread(()->{
            while (true){
                try {
                    //消费元素
                    System.out.println(blockingQueue.take());
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        //生产者线程
        Thread producer=new Thread(()->{
            Random random=new Random();
            while (true){
                try {
                    //生产元素
                    blockingQueue.put(random.nextInt(10000));
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        //启动线程
        consumer.start();
        producer.start();

        //等待线程执行完毕
        consumer.join();
        producer.join();

        //任务完成后的最后收尾
        System.out.println("生产者消费者执行完成");
    }
}

(代码实现时使用了lambda表达式,如对lambda不熟悉,可以参考lambda表达式-程序员宅基地)

到这里,一个生产者消费者模型的简单流程和实现就介绍完了~

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/a1806542392/article/details/136997005

智能推荐

C语言函数递归调用-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏22次。C语言函数递归调用_c语言函数递归调用

明日方舟抽卡模拟器wiki_明日方舟bilibili服-明日方舟bilibili服下载-程序员宅基地

文章浏览阅读410次。明日方舟bilibili服是一款天灾驾到战斗热血的创新二次元废土风塔防手游,精妙的二次元纸片人设计,为宅友们源源不断更新超多的纸片人老婆老公们,玩家将扮演废土正义一方“罗德岛”中的指挥官,与你身边的感染者们并肩作战。与同类塔防手游与众不同的几点,首先你可以在这抽卡轻松获得稀有,同时也可以在战斗体系和敌军走位机制看到不同。明日方舟bilibili服设定:1、起因不明并四处肆虐的天灾,席卷过的土地上出..._明日方舟抽卡模拟器

基于图像的目标检测与定位方法概述_图像定位算法-程序员宅基地

文章浏览阅读1.4w次,点赞15次,收藏97次。目录1. 目标检测与定位概念2. 目标检测与定位方法2.1 传统目标检测流程2.2 two-stage检测算法2.2.1 R-CNN2.2.2 two-stage其他算法2.2.2.1 Spatial Pyramid Pooling(空间金字塔池化)2.2.2.2 Fast-RCNN2.2.2.3 P11 Faster RCNN2.3 One-Stage2.3.1 YOLO2.3.2 SSD参考本文简单介绍基于图像的目标检测与定位相关概念,R-CNN和YOLO等算法基本思想。本文为学习笔记,参考了许多优_图像定位算法

数字图像处理Matlab-小波变换在图像处理中的应用(附代码)_小波分解与重构在图像处理的应用-程序员宅基地

文章浏览阅读9.8k次,点赞40次,收藏131次。目录1.Objectives:2.Experiment Content:3.Experiment Principle:4.Experiment Steps Result and Conlusion:1、了解各种小波性质2、观察各种小波函数及其尺度函数3、获得小波滤波器4、二维小波变换函数与重构函数5、查看及处理小波系数6、用小波变换进行图像压缩与边缘提取【附录】实现代码1.Objectives:..._小波分解与重构在图像处理的应用

如何把海思 Hi3556、Hi3559当ipc芯片使用_hi3556的固件可以刷hi3559吗-程序员宅基地

文章浏览阅读8k次。解决思路:1、网络方面:这两颗料没有网口,那么给linux系统端移植一颗usb转网卡的芯片即可,价格一两块RMB,可行。2、去掉middleware和reference层,直接在ndk层进行操作;3、如果对图像有要求,可以在相关接口扩展指令,从而达到间接使用mpi接口的目的;..._hi3556的固件可以刷hi3559吗

创龙TI OMAP-L138(定点/浮点DSP C674x+ARM9)RJ45以太网口_am1808 代换-程序员宅基地

文章浏览阅读466次。CPUOMAP-L138、TMS320C6748、AM1808三款CPU管脚兼容,外设资源基本相同。OMAP-L138TI公司的达芬奇架构嵌入式应用处理器开始使用DSP与ARM结合的非对称多核结构,OMAP-L138就是其中的一款低功耗双核嵌入式处理器。OMAP-L138双核架构兼具DSP的高数字信号处理性能和精简指令计算机(RISC)技术的优点,双核均是32位处理器。以下是OMAP-L138 CPU的资源框图:RJ45以太网口开发板采用了SMSC的LAN8710A网卡芯片,它可以自_am1808 代换

随便推点

Mysql递归调用,报错:Subquery returns more than 1 row-程序员宅基地

文章浏览阅读2.1k次。Mysql递归调用,报错:Subquery returns more than 1 row_subquery returns more than 1 row

割线定理-程序员宅基地

文章浏览阅读3.2k次。文字表达:从圆外一点引圆的两条割线,这一点到每条割线与圆交点的距离的积相等。数学语言:从圆外一点L引两条割线与圆分别交于A.B.C.D 则有 LA·LB=LC·LD=LT²。几何语言:∵割线LDC和LBA交于圆O于ABCD点∴LA·LB=LC·LD=LT²证明过程:证1:已知:如图直线ABP和CDP是自点P引的⊙O的两条割线求证:PA·PB=PC·PD证明:连接AD、BC∵∠A和∠C都对弧BD∴由圆周角定理,得 ∠DAP=∠BCP又∵∠P=∠P∴△ADP._割线定理

ThinkPHP3.2.3-文章管理系统-附带源码地址_thinkphp3.2.3 源码下载-程序员宅基地

文章浏览阅读6.1k次,点赞3次,收藏7次。一.前言本项目为文章管理系统,系统相对简单。但代码比较规范,适合作为第一个thinkphp项目,有需要的朋友可以看看。Thinkphp版本为3.2.3。涉及到的知识:验证码,文件上传、登录、自动完成、自动验证等。二.简介1.本系统有前台、后台两个模块。2.后台模块功能:栏目管理、文章管理、管理员信息修改。实现了需登录才可进入系统。3.前台_thinkphp3.2.3 源码下载

SpringMVC 中 Controller 是单例还是多例?如何保证并发安全?-程序员宅基地

文章浏览阅读1.4k次。点击上方“Java精选”,选择“设为星标”别问别人为什么,多问自己凭什么!下方有惊喜留言必回,有问必答!每一天进步一点点,是成功的开始...单例模式(Singleton)是程序设计中一种非常重要的设计模式,设计模式也是Java面试重点考察的一个方面。面试经常会问到的一个问题是:SpringMVC中的Controller是单例还是多例,很多同学可能会想当然认为Control..._controller是多线程的吗?如何保证线程安全

JS图片灯箱(lightBox)效果基本原理和demo-程序员宅基地

文章浏览阅读517次。 到年底了,项目不怎么忙,所以有空特地研究了下KISSY中源码JS灯箱效果,感觉代码比较简单,所以就按照他们的思路依赖于Jquery框架也封装了一个,特地分享给大家,以前经常看到网上很多这样的插件,感觉很多人很牛逼的样子,这样的效果也能做出来,碰巧今天自己也能研究出来一个,代码也不多,就300多行代码,嘿嘿!如果写的不够好,或者还不够的,希望大家多多指教!或者多多发表意见,那些需要值得..._$.lightbox

linux shell脚本字符串连接符,学习Linux shell脚本中连接字符串的方法-程序员宅基地

文章浏览阅读816次。这篇文章主要介绍了Linux shell脚本中连接字符串的方法,如果想要在变量后面添加一个字符,可以用一下方法:代码如下:$value1=home$value2=${value1}"="echo $value2把要添加的字符串变量添加{},并且需要把$放到外面。这样输出的结果是:home=,也就是说连接成功。又如代码如下:[root@localhost sh]# var1=http://www.3..._shell字符串连接符