【Java系列】多线程案例学习——基于阻塞队列实现生产者消费者模型

个人主页:兜里有颗棉花糖
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创
收录于专栏【Java系列专栏】【JaveEE学习专栏】
本专栏旨在分享学习JavaEE的一点学习心得,欢迎大家在评论区交流讨论💌
在这里插入图片描述

目录

  • 一、阻塞式队列
  • 二、生产者消费者模型
    • 生产消费者模型的优势
  • 三、生产者消费者举例代码(基于阻塞队列)
  • 四、基于阻塞式队列实现生产者消费者模型

一、阻塞式队列

什么是阻塞式队列(有两点):

  • 第一点:当队列满的时候,如果此时入队列的话就会出现阻塞,直到其它线程从队列中取走元素为止。
  • 第二点:当队列为空的时候,如果继续出队列,此时就会出现阻塞,一直阻塞到其它线程往队列中添加元素为止。

二、生产者消费者模型

什么是生产者消费者模型:
生产者消费者模型是常见的多线程编程模型,可以用来解决生产者和消费者之间的数据交互问题。

阻塞队列的最主要的一个目的之一就是实现生产者消费者模型(基于阻塞队列实现),生产者消费主模型是处理多线程问题的一种方式。

生产消费者模型的优势

生产者消费主模型的优势:针对分布式系统有两个优势,一个是解耦合(耦合我们可以理解为依赖程度)、另一个是削峰填谷

  • 解耦合:生产者和消费主之间通过缓冲区进行解耦合,而不会对彼此产生直接的依赖,我们通过引入生产者消费者模型(即阻塞队列)就可以达到解耦合的效果,但是付出的代价就是效率有所降低。

  • 削峰填谷:服务器接收到的来自用户端的请求数量可能会因为一些突发时间而暴增,此时服务器面临的压力就非常大了。我们要知道一台服务器承担的上限是一样的,不同的服务器所能承担的上限又是不同的。(机器的硬件资源(CPU、内存、硬盘、网络带宽等等)是有限的,而服务器每处理一个请求都需要消耗一定的资源,请求足够多直到机器的硬件资源招架不住的时候服务器也就挂了)通过引入生产消费者模型(即阻塞队列)就可以起到一个缓冲的作用,其中阻塞队列就承担了服务器的一部分压力,然后当峰值消退的时候,服务器接收到的请求就相对较少了,此时服务器由于阻塞队列的原因依然可以按照既定的顺序处理请求。

  • ‘’

阻塞队列只是一个数据结构,如果我们把这个数据结构单独实现称了一个服务器程序,并且使用单独的主机或者主机群来进行部署的话,此时阻塞式队列就进化成了消息队列。而在Java标准库中已经实现了阻塞队列,并且实现了三种阻塞队列的实现方式:

三、生产者消费者举例代码(基于阻塞队列)

生产消费者模型代码如下(基于阻塞式队列):

import java.util.concurrent.BlockingQueue;
  import java.util.concurrent.LinkedBlockingQueue;

// 生产消费者模型——阻塞队列
public class Demo20 {
    public static void main(String[] args) {
        // 创建一个阻塞队列来作为交易场所
        BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(10);
        Thread t1 = new Thread(() -> {
            int count = 0;
            while(true) {
                try {
                    queue.put(count);
                    System.out.println("生产元素:" + count);
                    count++;
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t2 = new Thread(() -> {
            while(true) {
                while(true) {
                    try {
                        Integer n = queue.take();
                        System.out.println("消费元素:" + n);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        t1.start();
        t2.start();
    }
}

代码运行结果如下:
在这里插入图片描述

四、基于阻塞式队列实现生产者消费者模型

现在,我们自己来基于循环队列来实现阻塞式队列。注意我们这里实现的阻塞队列是基于数组、基于循环队列的阻塞队列。

我们在实现阻塞队列的时候有以下几点需要注意:

  • 线程安全问题:需要给put方法take()方法进行加锁操作。
  • 经过加锁之后还需要考虑到内存可见性问题,这里就涉及到volatile关键字的使用。
  • 阻塞状态以及阻塞状态的解除时机要把握好(即wait()方法notify()方法的使用)。
  • wait()方法不一定是被notify()方法唤醒的,还有可能是被interrupt()方法唤醒的:如果interrupt方法是按照try catch的形式来进行编写的,一旦interrupt方法唤醒wait方法,接着执行完catch之后,代码并不会结束而是继续往后执行,此时就会出现覆盖元素的问题。(解决方法,使用while循环不断等待和检查条件。如果不使用 while 循环在状态被满足之前不断地等待和检查条件,就有可能在 wait 方法返回之后仍然不能安全地进行操作,这可能导致程序出现异常和错误。强烈建议使用wait方法的时候搭配while循环来判定条件

代码如下:

class MyBlockQueue {
    // 使用string类型的数组来保存元素,我们假设这里只存string
    private String[] items = new String[1000];
    //head表示指向队列的头部
    volatile private int head = 0;
    volatile private int tail = 0;
    volatile private int size = 0; // size表示元素个数
    
    private Object locker = new Object();
    
    public void put(String elem) throws InterruptedException {
        synchronized(locker) {
            while(size >= items.length) {
                //队列已满
                locker.wait();
                //return;
            }
            items[tail] = elem;
            tail++;
            if(tail >= items.length) {
                tail = 0;
            }
            //tail++和下面的if判断可以替换成tail = (tail + 1) % (items.length)
            //但是站在CPU的角度来看,其实还是简单的if判断比较快
            size++;
            locker.notify(); // 用来唤醒队列为空的阻塞情况
        }
    }
    //出队列
    public String take() throws InterruptedException {
        synchronized(locker) {
            while(size == 0) {
                locker.wait();
            }
            String elem = items[head];
            head++;
            if(head >= items.length) {
                head = 0;
            }
            size--;
            //使用notify来唤醒队列阻塞满的情况
            locker.notify();
            return elem;
        }
    }
}

public class Demo21 {
    public static void main(String[] args) {
        // 创建两个线程分别表示消费者和生产者
        MyBlockQueue queue = new MyBlockQueue();
        Thread t1 = new Thread(() -> {
           int count = 0;
           while(true) {
               try {
                   queue.put(count + "");
                   System.out.println("生产元素: " + count);
                   count++;
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        });
        Thread t2 = new Thread(() -> {
            while(true) {
                try {
                    String count = queue.take();
                    System.out.println("消费元素: " + count);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t1.start();
        t2.start();
    }
}

本文到这里就结束了,希望友友们可以支持一下一键三连哈。嗯,就到这里吧,再见啦!!!

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

案例260:基于微信小程序的签到系统的设计与实现

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder …

git 常用命令总结

git 工作原理图&#xff1a; git 常用命令及解释: 命令解释例子git init在当前目录初始化一个新的 Git 仓库。git initgit clone <repository>克隆一个远程仓库到本地。git clone https://github.com/example/repository.gitgit add <file>将文件的变化添加到暂存…

分享44个PyQt5源码总有一个是你想要的

分享44个PyQt5源码总有一个是你想要的 学习知识费力气&#xff0c;收集整理更不易。 知识付费甚欢喜&#xff0c;为咱码农谋福利。 链接&#xff1a;https://pan.baidu.com/s/1_5H_0Ydg0XUa1fz5Jok51Q?pwd6666 提取码&#xff1a;6666 项目名称 B站直播弹幕姬&#xff…

哪种猫粮比较好?怎样囤性价比高的主食冻干品牌 ?

在过去的100多年里&#xff0c;猫咪主食市场一直被膨化猫粮主导。然而&#xff0c;随着猫咪频频出现猝死、失明、发育不良以及营养不良等问题&#xff0c;猫主人们开始质疑膨化粮是否最适合猫咪。于是&#xff0c;从上世纪90年代开始&#xff0c;出现了生骨肉喂养。生骨肉确实是…

XV7081BB陀螺仪传感器

XV7081BB是一款用于自动化机器的数字输出型陀螺仪传感器&#xff0c;具有卓越的性能&#xff0c;尤其是偏置输出稳定性和低噪声。特点如下&#xff1a; 优良的偏置温度系数为0.0024(/s)/C。 ●低角度随机游走0.065/√h ●SPI/IC串行接口 集成的用户可选择的数字滤波器 ●角…

E : DS查找—二叉树平衡因子

Description 二叉树用数组存储&#xff0c;将二叉树的结点数据依次自上而下,自左至右存储到数组中&#xff0c;一般二叉树与完全二叉树对比&#xff0c;比完全二叉树缺少的结点在数组中用0来表示。 计算二叉树每个结点的平衡因子&#xff0c;并按后序遍历的顺序输出结点的平衡…

mybatisX自动生成sql语句,尝试测试方法报错

今天我使用mybatisx自定义mapper方法生成sql语句后&#xff0c;在测试时报错 错误是MyBatis 无法找到映射的语句&#xff08;Statement&#xff09;引起的 我是这样操作的&#xff0c;在mapper接口自定义了一个方法 然后alt加enter&#xff0c;自动生成sql 结果 mapper.xml文件…

31.Java程序设计-基于Springboot的鲜花商城系统的设计与实现

引言 背景介绍&#xff1a;鲜花商城系统的兴起和发展。研究目的&#xff1a;设计并实现一个基于Spring Boot的鲜花商城系统。论文结构概述。 文献综述 回顾相关鲜花商城系统的设计与实现。分析不同系统的优缺点。强调Spring Boot在系统设计中的优越性。 系统设计 需求分析 用户…

css中sprite(css精灵)是什么,有什么优缺点

概念 将多个小图片拼接到一个图片中 。通过 background-position 和元素尺寸调节需要显示的背景图案。 优点 减少 HTTP 请求数&#xff0c;极大地提高页面加载速度 增加图片信息重复度&#xff0c;提高压缩比&#xff0c;减少图片大小 更换⻛格方便&#xff0c; 只需在一张或…

mysql保姆安装教程

一.下载install文件 1.进入Mysql官网&#xff0c;点击下载 2.选择MySQL Installer for Windows 3.推荐选择第二个安装包 4.不登陆&#xff0c;开始下载 5.等待下载完成 二.安装前的配置 通过电脑“设置”&#xff0c;检查电脑是否包含中文名&#xff0c;如果包含请重命名 …

生活常识-如何开社保证明(四川)

下载并打开天府市民云APP 注册后登陆 点击社保服务 点击社保证明 点击【四川省社会保险个人社保证明名(近24个月)】 点击下载 下载后点击【QQ发送给好友&#xff0c;然后发送给自己的电脑设备(我的电脑)】

通过C++程序实现光驱的自动化刻录和读取

文章目录 ISO文件格式光盘的基本概念光盘种类特点DVDR光盘使用windows调用Linux调用Linux平台下用到的C库:读取设备驱动列表向光驱中写文件 数字存储媒体快速发展的今天&#xff0c;光驱的使用已经不像以前那样普及了。但是在数据备份、安装软件和操作系统、旧设备兼容等领域还…

LTPI协议的理解——LTPI协议的定义和结构

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 LTPI协议的理解——LTPI协议的定义和结构 定义DC-SCM 2.0 LTPI 结构GPIO通道I2C/SMBus通道Uart通道OEM通道数据通道 总结 定义 LTPI (LVDS Tunneling Protocol & Interf…

算法基础之计数问题

计数问题 核心思想&#xff1a; 数位dp / 累加 累加 ​ 分情况讨论 &#xff1a; xxx 000 ~ abc –1 yyy 000 ~ 999 共 abc * 1000 种 特别地&#xff0c;当枚举数字0时 (找第4位为0的数) 前三位不能从000开始了 否则没这个数不合法(有前导零) xxx abc 2.1. d < 1 , 不…

拥抱健康,远离内耗:程序员必备的情绪管理策略

程序员是一群特别脆弱的群体&#xff0c;俗称IT民工&#xff01; 每天上班要跟产品斗智斗勇&#xff0c;还要跟bug斗的难解难分&#xff0c;另外还要被领导批&#xff0c;跟同事扯皮&#xff0c;整个一天下来常常筋疲力尽。 程序员大多不善言语&#xff0c;受了委屈往往喜欢吞到…

抓包工具Charles安装及使用

Charles 介绍 Charles 是在 Mac 下常用的网络封包截取工具&#xff0c;在做 移动开发时&#xff0c;我们为了调试与服务器端的网络通讯协议&#xff0c;常常需要截取网络封包来分析。 Charles 通过将自己设置成系统的网络访问代理服务器&#xff0c;使得所有的网络访问请求都…

GameFi 2024年或将迎来新的爆发!

在数字时代&#xff0c;游戏已经不仅仅是一种娱乐方式&#xff0c;更是一种跨越现实和虚拟界限的全球性文化现象。而游戏金融&#xff08;GameFi&#xff09;正是这场数字革命的下一个巨大风潮。 随着科技的不断发展和创新&#xff0c;2024年&#xff0c;GAMEFI&#xff08;Gam…

购买腾讯云服务器需要多少钱?购买腾讯云服务器方法教程

腾讯云轻量应用服务器购买指南&#xff0c;有两个入口&#xff0c;一个是在特价活动上购买&#xff0c;一个是在轻量应用服务器官方页面购买&#xff0c;特价活动上购买价格更便宜&#xff0c;轻量2核2G3M带宽服务器62元一年起&#xff0c;阿腾云atengyun.com分享腾讯云轻量应用…

【最新报道】初窥Windows AI 工作室

自我介绍 做一个简单介绍&#xff0c;酒研年近48 &#xff0c;有20多年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0e;因为工作需要&#xff0c;另外也因为兴趣涉猎比较广&#xff0c;为了自己学习建立了三个博客&#xff0c;分别是【全球IT瞭望】&#xff0c;【…

Python+OpenCV 零基础学习笔记(6):ROI

文章目录 相关链接运行环境前言ROI颜色区域分割颜色通道合并 相关链接 【2022B站最好的OpenCV课程推荐】OpenCV从入门到实战 全套课程 CSDN标题里个括号对应视频的分P OpenCVPython CSDN专栏 Gitee 项目地址 运行环境 Python:3.11.5Anaconda:23.7.4IDE:vscode运行环境&#x…