并发编程-生产者消费者模式Java代码实现

2023-05-16

并发编程-生产者消费者模式Java代码实现

生产者消费者模式

  1. 生产者仅负责产生结果数据,不关心数据该如何处理,而消费者专心处理结果数据。

  2. 消息队列是有容量限制的,满时不会再加入数据,空时不会再消耗数据。

消费队列可以用来平衡生产和消费的线程资源。

在这里插入图片描述
代码如下:

  1. 使用双向链表和Synchronized锁来实现消息队列。
  2. 使用Excutors中的创建线程池的方法模拟生产者和消费者线程。

其他可见代码中的注释。

import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;

public class MessageTest {
    public static void main(String[] args) {
        // 创建生产者线程池,总共3个线程,并且传入自定义的线程工厂,这样可以方便给线程起名
        ExecutorService producer = Executors.newFixedThreadPool(3, new ThreadFactory() {
            private AtomicInteger t = new AtomicInteger(1);
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "生产者-" + t.getAndIncrement());
            }
        });
        // 创建消费者线程池,总共3个线程,并且传入自定义的线程工厂,这样可以方便给线程起名
        ExecutorService consumer = Executors.newFixedThreadPool(2, new ThreadFactory() {
            private AtomicInteger t = new AtomicInteger(1);
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "消费者-" + t.getAndIncrement());
            }
        });

        // 新建消息队列,队列容量为2
        MessageQueue<Message> queue = new MessageQueue<>(2);

        // 生产者产生消息
        for (int i = 0; i < 5; i++) {
            int id = i;
            producer.submit(()->{
                queue.put(new Message(id, "value : " + id));
            });
        }

        // 消费者消费消息
        for (;;) {
            consumer.submit(()->{
                Message take = queue.take();
            });
        }
    }
}

class MessageQueue<T>{
    /*
      消息队列的定义,使用LinkedList作为存储消息的数据结构,这样可以将生产的消息直接放入
      队列尾部,消费消息时从头部直接获取。消息的类型定义为泛型。
     */
    //存储消息的链表
    private LinkedList<T> list = new LinkedList<>();
    // 消息队列容量
    private int capacity;

    public MessageQueue(int capacity) {
        this.capacity = capacity;
    }

    public T take(){
        // 消费者线程取数据, 因为设计到多线程的对共享变量的访问,所以需要加锁,此处也可以使用ReentrantLock加锁
        // 此处对变量list加锁,也可以直接对this加锁
        synchronized (list){
            // 获得当前访问线程的名称
            String t_name = Thread.currentThread().getName();
            // 判断消息队列是否为空,为空则阻塞,生产者线程放入数据后唤醒
            while(list.isEmpty()){
                System.out.println("["+t_name+"]"+" 队列为空,消费者线程等待...");
                try {
                    list.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            // 不为空则取消息
            T message = list.removeFirst();
            // 打印操作信息
            System.out.println("["+t_name+"]"+" 消费消息: " + message.toString());
            // 唤醒阻塞中的线程
            list.notifyAll();
            return message;
        }
    }

    public void put(T message){
        // 生产者线程放入数据, 因为设计到多线程的对共享变量的访问,所以需要加锁,此处也可以使用ReentrantLock加锁
        // 此处对变量list加锁,也可以直接对this加锁
        synchronized (list){
            // 获得当前访问线程的名称
            String t_name = Thread.currentThread().getName();
            // 判断消息队列是否已满,满则阻塞,消费者线程消费数据后唤醒
            while(list.size()==capacity){
                System.out.println("["+t_name+"]"+" 队列已满,生产者线程等待...");
                try {
                    list.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            // 不满则放入消息
            list.addLast(message);
            // 打印操作信息
            System.out.println("["+t_name+"]"+" 生产消息: " + message.toString());
            // 唤醒阻塞中的线程
            list.notifyAll();
        }
    }
}

class Message{
    // 消息id
    private int id;
    // 消息的值
    private String value;

    public Message(int id, String value) {
        this.id = id;
        this.value = value;
    }

    public int getId() {
        return id;
    }

    public String getValue() {
        return value;
    }

    @Override
    public String toString() {
        return "Message{" +
                "id=" + id +
                ", value='" + value + '\'' +
                '}';
    }
}

运行结果:
在这里插入图片描述
可以看到首先消费者线程消费,但是队列为空,则线程阻塞等待,之后生产者-1和生产者-3生产消息,但是因为队列容量为2,当生产者-2想要继续放入消息时,被阻塞。之后消费者-2进行消费消息之后,生产者-2被唤醒又可以将消息放入到消息队列中去…

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

并发编程-生产者消费者模式Java代码实现 的相关文章

  • Windows重建EFI引导启动分区(esp分区)

    Windows重建EFI引导启动分区 xff08 esp分区 xff09 遇到这种情况windows已经无法启动 xff0c 所以需要u盘启动盘进入winPE系统 1 如果只是格式化了esp分区 xff0c 没有改变esp分区的类型 xff
  • 智能革命和未来社会《智能时代--大数据和智能革命重新定义未来》

    通过区块链 xff08 Block Chain xff09 在未来跟踪每一件商品从制造出来到被消费的完整行踪 比特币在一定程度上起到货币的作用 xff0c 并且成为全球很安全的洗钱工具 xff0c 源于它背后的一个技术 区块链 block即
  • cas 单点登陆实战-sso-config篇(五)

    本篇我们讲解cas单点登陆在与shiro集成 xff0c 在与redis集成遇到的问题 先看完整代码吧 package com madnet config import com google common base CaseFormat i
  • cas 登陆时验证信息无效

    1 先查看缓存中的地址等是否正确 xff0c 不正确清除缓存重新打包 2 检查证书是否正确
  • crontab任务堆积导致启动大量进程的处理(flock)

    crontab在执行任务过程中 xff0c 可能由于任务执行错误或者在下一个任务开始前 xff0c 前一个任务没有执行完成 xff0c 导致大量的进程产生 xff0c 最后导致死机等 可以使用flock来加锁防止启动大量进程 xff1a f
  • Ue4行为树学习笔记 二

    Ue4行为树学习笔记 二 前言引用资料 行为树创建于布局任务设立 追逐随机巡逻AI控制器的设置最终设置尾声 前言 因为篇幅原因 xff0c 没看过上篇还请移步至 Ue4行为树学习笔记 一 引用资料 行为树快速入门指南 UE4学习笔记 xff
  • Python实现人脸识别

    文章目录 前言一 face recognition的安装1 安装dlib1 安装face recognition 二 上源码总结 前言 face recognition face recognition中文使用说明 号称是世界上最简单的开源
  • GPU, CUDA,cuDNN三者的关系总结

    GPU CUDA cuDNN三者的关系总结 CPU 和 GPU cpu和gpu结构展示 GPU xff08 图像处理器 xff0c Graphics Processing Unit xff09 和CPU xff08 中央处理器 xff0c
  • android应用内多进程的实现

    Android应用内多进程的介绍 正常情况下 xff0c 一个apk启动后只会运行在一个进程中 xff0c 其进程名为AndroidManifest xml文件中指定的应用包名 xff0c 所有的基本组件都会在这个进程中运行 但是如果需要将
  • 只需两步获取任何小程序源码

    前言 xff1a 这个博文的转载挺多的 xff0c 不过原文在更新 xff0c qwerty472123大神的脚本也在更新 xff0c 好多文章转载后就不再更新了 xff0c 看以前的步骤操作 xff0c 可能会引起奇怪的bug 这种方法
  • linux环境变量、交叉编译工具链gcc

    linux环境变量 1 linux环境变量 Linux 是一个多用户操作系统 xff0c 每个用户都有自己专有的运行环境 用户所使用的环境由一系列变量所定义 xff0c 这些变量被称为环境变量 系统环境变量通常都是大写 每个用户都可以根据需
  • Ubuntu解决登录界面无限循环

    由于配置scala和spark xff0c 修改了 etc profile文件 xff0c 导致Ubuntu登录界面无线循环 解决方法 xff1a 将profile修改正确 这是我的正确的文件内容 xff0c 供参考 span class
  • 如何优化Win11右键菜单

    Win 11 微软已经在10月5日发布了Windows 11正式版 xff0c 很多朋友也已经升级了 不过对于Win11的一些新设计 xff0c 并不是所有人都能适应的 xff0c 例如新的右键快捷菜单 xff0c 就不少朋友表示接受不了
  • 简单消费者组件的抽象思考(C++11)

    异步输出日志 平时开发过程中总是不可避免会用到生产者 消费者模型来实现一些具体的功能 比如在应用程序中 xff0c 我们希望在关键的代码附近输出一些日志 到文件 xff0c 以备程序运行出现bug时尽可能地知道更多的运行时信息 xff0c
  • 利用Cloudflare API批量添加域名至Cloudflare账户

    在Cloudflare中其实是有提供API的 xff0c 可以利用其功能进行批量添加域名 xff0c 在这篇文章中 xff0c 我将尝试看看如何解决这个问题 第一 准备工作 1 拥有一个Cloudflare账户 2 需要执行脚本的Linux
  • 如何用vnc远程连接mac系统

    在mac os系统安装好后 xff0c 怎么用vnc来进行远程连接呢 xff0c 步骤在下方 xff1a 1 打开系统偏好设置 2 点击共享 3 勾选屏幕共享 选择允许访问的用户 点击电脑设置 4 填好vnc连接的密码 5 用vnc登录 x
  • 学生时代的书单

    大话系列的书 xff0c 用独特的行文风格 xff0c 以风趣 幽默的语言向读者讲述 概念原理知识 xff0c 用漫画式的插图帮助读者理解晦涩 枯燥的技术 xff0c 让我们在快乐中掌握知识 xff01 1 大话通信 通信基础知识读本 作者
  • NLTK语料库nltk.download()安装失败及下载很慢的解决方法

    一 解决nltk download 安装失败 import nltk nltk download 下载nltk语料库出现getaddrinfo failed 如下错误 xff1a 这里只需将Server Index路径改成NLTK官网htt
  • windows虚拟机ping不通解决方法

    防火墙在作祟 简单暴力方法一 xff1a 直接关了防火墙 安全操作方法二 xff1a 打开入站规则就OK 如果是端口不通 xff0c 新建个端口规则解决啦
  • Spring框架(一)---------基本配置

    一 spring框架的配置一般姿势 1 导包 2 创建对象 3 配置文件 xff08 src applicationContext xml xff09 3 1 导入约束 3 2 配置applicationContext xml文件 3 3测

随机推荐

  • windows下面notepad++编写的文件未保存,电脑死机,文件找回

    notepad恢复未保存的文件 xff0c 备份文件 C Users 你当前用户的用户名 AppData Roaming Notepad 43 43 backup可以恢复 如果找不到此文件 因为文件被隐藏了 xff0c 打开隐藏文件即可 抖
  • idea自带的Maven添加阿里镜像

    打开idea xff0c 并打开设置 在搜索框查找Maven xff0c 可以看到idea使用的Maven路径 xff0c 配置文件路径 xff0c 以及仓库路径 重点是看配置文件 xff1a settings xml 如果在配置文件路径下
  • Ubuntu16.04开机失败—进入tty1终端修复

    Ubuntu16 04开机失败 进入tty1终端修复 如图所示 xff0c 我的Ubuntu16 04开机的时候报错 xff0c 提示 etc profile 文件的第34行出错 我想起了这个是自己安装mysql和sqoop的时候配的路径
  • 下载网页中的视频的两种方法

    方法一 xff1a 使用360或者IE浏览器 1 进入播放视频的网页 xff0c 播放视频并缓冲完全 xff1b 2 点击浏览器 工具 栏菜单中 Internet 选项 xff1b 3 在弹出的窗口中间部位找到 设置 xff1b 4 在新窗
  • tigerVNC的简单使用教程(CentOS的远程桌面连接)

    tigerVNC的简单使用教程 xff08 CentOS的远程桌面连接 xff09 DayDreamingBoy的博客 CSDN博客 tigervnc 1 环境和软件准备 1 CentOS 6 3下 root 64 localhost rp
  • gazebo视角调整

    看见上图中的橘黄色的图标了吗 xff1f 点击下拉框 xff0c 就可以调整自己的视角 xff0c 然后配合Ctrl 43 鼠标拖拽就OK了 参考博客 参考一
  • RTX 线程通信之——内存池

    文章目录 Memory Pool为什么需要内存池 xff1f 什么是内存池 xff1f RTX内存池API 案例 xff1a 按键控制LED灯定义相关创建相关执行相关实验效果 小结参考资料 Memory Pool 内存池 Memory Po
  • springboot项目多环境配置及常见配置名的含义

    强烈推荐大家想学习springboot项目相关知识的 xff0c 可以看一下Gitee上大佬整理的Spring Boot基础教程 xff0c 非常适合初学者和进阶学习 xff1a 传送门 我们在进行项目开发时 xff0c 经常同一个应用需要
  • 聊聊linux中的文件种类、文件名、文件扩展名

    linux中的文件种类 文件名 文件扩展名详解 在使用 ls l指令后可以看到文件的类型 xff0c 其中第一个字符就是代表的文件的类型 xff0c 常见的文件类型是一般文件 和目录文件d 文件的类型 1 正规文件 xff08 regula
  • 华为2288 v5服务器安装centos7.9教程

    华为2288 v5服务器安装centos7 9教程 一 准备工作二 centos启动盘制作三 删除 配置RAID四 选择启动项1 开机按F112 选择u盘启动 五 centos安装1 选择语言2 选择安装方式3 选择安装位置 xff08 重
  • Pytorch-gpu版安装教程【注意:无需提前安装cuda和cudnn】

    Pytorch gpu版安装教程 注意 xff1a 无需提前安装cuda和cudnn 1 首先确保你已经安装好Anaconda2 查看自己电脑上显卡的信息 xff0c 通过显卡控制面板查看3 如何根据想要的cuda的版本下载相应的显卡驱动程
  • python调用有道翻译API进行翻译

    python调用有道翻译API进行翻译 步骤 python调用有道翻译API进行翻译准备调用API所需的APPID以及秘钥1 有道智云注册账号2 有道智云注册账号3 创建实例 xff0c 绑定应用4 查看官方文档 python实现对有道翻译
  • Linux安装cuda10.2

    Linux安装cuda10 2 安装其他版本的cuda也可以参考以下步骤 A 进入NVIDIA官网下载安装文件 百度搜索cuda 10 2 点开第一个网页 找到对应自己系统版本的安装文件命令 在命令行中执行给出的代码 xff0c 下载安装文
  • Windows 10 安装anaconda

    Windows 10 安装anaconda 1 下载anaconda安装包2 安装Anaconda3 配置Anaconda环境变量4 检验是否安装成功4 anaconda换源5 python换源 1 下载anaconda安装包 网页搜索清华
  • 排序算法-基数排序

    排序算法 基数排序 算法思想 基数排序是采用多关键字排序思想 xff08 即基于关键字各位的大小进行排序地 xff09 xff0c 借助 分配 收集 两种操作对单逻辑关键字进行排序 基数排序又分为最高位优先 MSD 降序 排序和最低位优先
  • No module named ‘cv2‘ 解决方法

    No module named cv2 解决方法 1 安装opencv python 在使用的虚拟环境中 xff0c 输入以下命令 pip span class token function install span opencv pyth
  • AttributeError:module ‘distutils‘ has no attribute ‘version

    AttributeError module distutils has no attribute 39 version 在使用torch utils tensorboard时 xff0c 出现错误 xff1a 出错语句from torch
  • CPU、GPU、NPU的区别

    CPU GPU NPU的区别 CPU CPU xff08 CentralProcessing Unit xff09 中央处理器 xff0c 是一块超大规模的集成电路 xff0c 主要逻辑架构包括控制单元Control xff0c 运算单元A
  • jdk(Linux+Windows)环境变量配置

    Windows jdk环境变量配置 xff1a PATH JAVA HOME bin JAVA HOME jre bin CLASSPATH JAVA HOME lib JAVA HOME lib tools jar JAVA HOME l
  • 并发编程-生产者消费者模式Java代码实现

    并发编程 生产者消费者模式Java代码实现 生产者消费者模式 生产者仅负责产生结果数据 xff0c 不关心数据该如何处理 xff0c 而消费者专心处理结果数据 消息队列是有容量限制的 xff0c 满时不会再加入数据 xff0c 空时不会再消