阻塞队列(BlockingQueue)的实现和使用

阻塞队列(BlockingQueue)

文章目录

  • 阻塞队列(BlockingQueue)
    • 阻塞队列的梗概
      • 解耦合和削峰填谷
    • java代码实现一个阻塞队列

阻塞队列的梗概

众所周知,队列是一种数据结构,符合先进先出的结构,先进先出就是指先到达队列的元素最先出队列。队列对数据的操作一般有三种:入队列,出队列,获取队首元素。而这里的阻塞队列只有两种操作:入队列,出队列,一般是不需要获取队首元素的。阻塞队列是可以用于存放线程,因为阻塞队列可以对线程安全进行一种保护策略,当一个在队列中取一个线程时,如果阻塞队列中无线程,则会陷入等待状态,也就是阻塞,同样的,当队列空间满了之后,想要再加入线程,也会进入等待状态。无线程只有当加入线程才会解开无线程的阻塞,也就是解锁,线程满时只有当线程出队列才会解锁。

阻塞队列对多线程进行数据交互,非常友好。与队列相同,阻塞队列只是增加了阻塞特性,把查看队首元素功能去除,因为对于阻塞队列该功能用处不大。

使用官方阻塞队列

//这里的BlockingQueue是一个接口类型的类,不能直接new,所有可以new实现类,向下转型
//BlockingQueue主要有两个实现类(读者请根据需求创建)
//1.数组实现类
//2.链表实现类
BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
BlockingQueue<Integer> queue1 = new LinkedBlockingDeque<>();

注意这里对数组实现类必须指定大小,该实现类中只有三个构造方法。

在这里插入图片描述

这里演示一个生产者消费者模型更有助于理解:

//阻塞出队列时队列为空时
public class ThreadDomeTest {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<Integer> queue = new ArrayBlockingQueue(10);
        Thread t1 = new Thread(()->{
            //取出元素
            while (true){
                try {
                    int value = queue.take();
                    System.out.println("消费"+value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        });
        Thread t2 = new Thread(()->{
            int value = 0;
            //输入数据
            while(true){
                System.out.println("生产"+(++value));
                try {
                    queue.put(value);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
    }
}

在这里插入图片描述

可以看见两个模块之间一个线程进行生产,一个线程进行消费,进程正常运行。

这里演示一个基于消费者模型,进入(入队列不过队列已经满)情况的阻塞状态,更有助于理解:

public static void main(String[] args) throws InterruptedException {
    //这里将阻塞队列默认大小设置为10
        BlockingQueue<Integer> queue = new ArrayBlockingQueue(10);
        Thread t1 = new Thread(()->{
            //取出元素
            //这里我将出队列的循环语句注释,表示可以出,但是只出一个
//            while (true){
                try {
                    int value = queue.take();
                    System.out.println("消费"+value);
                } catch (InterruptedException e) {
                    e.printStackTrace();
//                }
            }

        });
        Thread t2 = new Thread(()->{
            int value = 0;
            //输入数据
            while(true){
                System.out.println("生产"+(++value));
                try {
                    queue.put(value);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
    }

在这里插入图片描述

阻塞队列主要解决两部分的问题:

  1. 可以让上下两部分的模块实现更好的“解耦合”
  2. 削峰填谷

解耦合和削峰填谷

这里消费者和生产者是两个不同的个体,也就是上下的两部分,我们常说的“高内聚低耦合”,高内聚是指代码的分布比较均匀,一个功能的代码就聚合在一起,使得程序员想修改一段代码时,可以轻易找到,也就是指关联代码分门别类的规制起来。低耦合是两个不同模块代码的相互影响程度,主要是想将两段代码的影响程度降低,也就是两个模块的关联关系的强弱之分。

削峰填谷是当一个任务量足够大的时候会出现一个任务波峰,而另一个与其关联的代码段并不知道对方出现了任务波峰。而当该任务空间足够大时,就可以将其波峰降低。

在这里插入图片描述

要满足上图,需要在满足阻塞队列的前提下,扩展更多功能,使得其变成单独服务器,一般要使得上图顺利进行,可以选择扩充阻塞队列的大小,也可以增加一个额外的中转站,相当于模块A中任务要经过C中转站进入到B线程中,A和B在不知道对方存在的情况下交换数据,进一步的保障了线程安全,也提高了处理任务的效率。

分析削峰填谷,主要是针对上图时刻二时,在爆发式变高的峰值中两个模块会互相影响,在B模块模块中如果没有设置请求峰值处理机制或是B模块资源不足情况下,程序可能会崩溃!!如果在模块A与B中加入服务器模块,则由服务器承担A模块中的任务压力,B模块按正常速度运行即可,削峰就是如此。填谷是指,当业务在减少前有一波波峰在前,B模块依旧可以以平稳的效果处理业务。(相当于水利工程——三峡大坝,在雨水充足时,挡住水对农田的冲击,在干旱时,适当放低坝的高度

java代码实现一个阻塞队列

我们知道阻塞队列是一个相当于队列的数据结构,主要与队列不同的地方就是可以产生阻塞

实现一个阻塞队列主要分为3步:

  1. 实现一个普通队列
  2. 加上线程安全
  3. 实现阻塞功能

这里我用数组来表示阻塞队列,如果读者想用其他方法,欢迎交流。

public class blockQueue01 {
	private int[] array= new int[1000];//数组的总大小
    private int usesize;//使用了的大小
    private int input;//输入的下标
    private int output;//输出的下标
    //输入队列方法,直接对方法进行加锁操作
    synchronized public void put( int val) throws InterruptedException {
        if(isFull()){
          this.wait();
        }
        array[input]=val;
        input++;
        usesize++;
        //判断是否越界
        if(input == array.length){
            input=0;
        }
        this.notify();
    }
    //判断队列是否满
    private boolean isFull(){
        return usesize==array.length;
    }
     //输出队列方法
    synchronized public int take() throws InterruptedException {
        if(isEmpty()){
            this.wait();
        }
        int value = array[output];
        output++;
        //判断是否越界
        if(output == array.length){
            output = 0;
        }
        usesize--;

        this.notify();
        return value;
    }
}

使用自己创建的阻塞队列写一个生产者消费者模型:

class Test{
    public static void main(String[] args) throws InterruptedException {
        blockQueue01 queue = new blockQueue01();
        Thread t1 = new Thread(()->{
            //取出元素
            while (true){
            try {
                int value = queue.take();
                System.out.println("消费"+value);
            } catch (InterruptedException e) {
                e.printStackTrace();
                }
            }

        });
        Thread t2 = new Thread(()->{
            int value = 0;
            //输入数据
            while(true){
                System.out.println("生产"+(++value));
                try {
                    queue.put(value);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t1.start();
        t2.start();
    }
}

在这里插入图片描述

可以正常使用,这里我们主要讲解了阻塞队列的实现以及使用,和阻塞队列与普通队列的区别,还有阻塞队列的线程安全问题。这里提出一个小建议,在Java官方中不建议在if中使用wait方法,可能会因为系统随机调度而中断notify的使用,使得wait无法获得唤醒也就会导致死等的存在
如果还有其他想法的小伙伴欢迎交流(。・∀・)ノ

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

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

相关文章

【动态绘图】python可视化--丝滑版

✅作者简介&#xff1a;在读博士&#xff0c;伪程序媛&#xff0c;人工智能领域学习者&#xff0c;深耕机器学习&#xff0c;交叉学科实践者&#xff0c;周更前沿文章解读&#xff0c;提供科研小工具&#xff0c;分享科研经验&#xff0c;欢迎交流&#xff01;&#x1f4cc;个人…

鼎桥通信,拥抱基础创新的“高灵活性”时代

作者 | 曾响铃 文 | 响铃说 伴随数智化转型成为时代变革大方向&#xff0c;一批走在时代前端的数智化转型企业应运而生&#xff0c;不断丰富5G、物联网等新兴技术的应用场景&#xff0c;构建万智互联的产业生态。作为国内通信领域的引领者&#xff0c;鼎桥通信技术有限公司&a…

AF染料试剂Alexa fluor 680 PEG Biotin,AF680 PEG Biotin,荧光强度稳定利于多种荧光标记

文章关键词&#xff1a;AF染料试剂&#xff0c;AF680&#xff0c;PE-Biotin衍生物Alexa fluor 680 PEG Biotin&#xff0c;AF680 PEG Biotin | Alexa fluor 680-PEG-生物素| CAS&#xff1a;N/A | 纯度&#xff1a;95%试剂参数信息&#xff1a; CAS&#xff1a;N/A 外观&am…

docker使用

dokcer 安装 # 1、yum 包更新到最新 yum update # 2、安装需要的软件包&#xff0c; yum-util 提供yum-config-manager功能&#xff0c;另外两个是devicemapper驱动依赖的 yum install -y yum-utils device-mapper-persistent-data lvm2 # 3、 设置yum源 yum-config-manager …

精确性和准确性是两码事儿

准确性(Accuracy)是与正确答案的接近程度&#xff0c;精确性(Precision)是对这个答案的分辨率。 假设&#xff0c;你问我&#xff0c;”现在几点了?” 我抬头看看太阳&#xff0c;然后估算了一下&#xff0c;回答道 “现在是上午 10 点 35 分 22.131 秒” 我给出的是一个足…

Nacos配置中心优雅配置JSON数据格式

在我业务开发中&#xff0c;需要在配置中心配置Json数据&#xff0c;返回给前端。因Nacos默认不支持Json格式配置&#xff0c;需要搭配监听器获取配置中心Json数据&#xff0c;返回给客户端。二、搭配Nacos配置Josn数据1. bootstrap.ymlserver:port: 9000 spring:application:n…

Vue使用ElementUI对table的指定列进行合算

前言 最近有一个想法&#xff0c;就是记录自己花销的时候&#xff0c;table中有一项内容是花销的金额。然后想在table的底部有一项内容是该金额的总计。 然后我就顺着elementui的table组件寻找相关的demo&#xff0c;还真发现了一个这样的demo。 对于这个demo&#xff0c;官方…

SSH框架整合教程

工程目录结构如下&#xff1a; 本工程只介绍SSH整合的基本流程&#xff0c;所以没有写接口 1. 导入jar包 <dependencies><!--hibernate包--><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId>…

【各种安装2】

各种安装2一、八阶段-第四章-案例导入说明1.安装MySQL1.1.准备目录1.2.运行命令1.3.修改配置1.4.重启2.导入SQL3.导入Demo工程3.1.分页查询商品3.2.新增商品3.3.修改商品3.4.修改库存3.5.删除商品3.6.根据id查询商品3.7.根据id查询库存3.8.启动4.导入商品查询页面4.1.运行nginx…

Linux线程同步与互斥(二)/生产消费者模型

⭐前言&#xff1a;本文会先后讲解生产消费者模型、条件变量和基于阻塞队列的生产消费者模型。 1.生产消费者模型 什么是生产消费者模型&#xff1f; 认识生产消费者模型 使用学生&#xff08;消费者&#xff09;&#xff0c;超市&#xff0c;供货商&#xff08;生产者&…

C++ 26 常用算法

目录 一、概述 1.1 常用遍历算法 1.1.1 算法简介 1.1.2 for_each遍历算法 1.1.3 transform遍历算法 1.2 常用查找算法 1.2.1 算法简介 1.2.2 find 查找算法 1.2.3 find_if 查找算法 1.2.4 adjacent_find 查找算法 1.2.5 binary_search 查找算法 1.2.6 count 查找算法…

【面试题】JS的一些优雅写法 reduce和map

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 JS的一些优雅写法 reduce 1、可以使用 reduce 方法来实现对象数组中根据某一key值求和 …

LFM雷达实现及USRP验证【章节3:连续雷达测距测速】

第一章介绍了在相对速度为0时候的雷达测距原理 目录 1. LFM测速 1.1 雷达测速原理 1.2 Chrip信号测速 2. LFM测速代码实现 参数设置 仿真图像 matlab源码 代码分析 第一章介绍了在相对速度为0时候的雷达测距原理&#xff0c;第二章介绍了基于LFM的雷达测距原理及其实现…

数据结构第十一期——线段树的原理和应用

目录 一、前言 二、线段树的概念 1、区间最值问题RMQ (Range Minimum/Maximum Query) &#xff08;1&#xff09;暴力法 &#xff08;2&#xff09;高效的办法&#xff1a;线段树 &#xff08;3&#xff09;把数列放在二叉树上 &#xff08;4&#xff09;查询最小值的复…

43-二叉树练习-LeetCode236二叉树的最近公共祖先

题目 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个节点 p、q&#xff0c;最近公共祖先表示为一个节点 x&#xff0c;满足 x 是 p、q 的祖先且 x 的深度尽可能大&#xff08;一个节点也可以是它…

一款全新的基于GPT4的Python神器,关键还免费

chartgpt大火之后&#xff0c;随之而来的就是一大类衍生物了。 然后&#xff0c;今天要给大家介绍的是一款基于GPT4的新一代辅助编程神器——Cursor。 它最值得介绍的地方在于它免费&#xff0c;我们可以直接利用它来辅助我们编程&#xff0c;真正做到事半功倍。 注意&#…

k8s实践 | configmapsecretpvpvc

文章目录configmap&secret&pv&pvc一、configMap1、应用场景2、创建configMap2.1、help文档2.2、使用目录创建2.3、根据文件创建2.4、文字创建2.5、直接方法2.6、pod中应用2.7、热更新二、secret1、Service Account2、opaque Secret2.1、创建示例2.2、使用方式三、k…

eNSP 本地AAA配置实验

关于本实验本实验要求将路由器AR1配置为AAA服务器&#xff0c;以本地认证方式对尝试登录AR1的用户进行身份认证和授权。路由器AR2作为登录用户&#xff08;AAA客户端&#xff09;&#xff0c;以Telnet的方式登录AR1.读者需要在AR1中创建一个名为datacom的管理员域&#xff0c;并…

【Unity游戏开发教程】零基础带你从小白到超神22——旧动画和新动画组件的使用

制作一个动画 创建动画 添加变化属性 实现方块向右移动10 添加关键帧 实现先慢后快的效果 录制动画 旧动画组件(Animation组件) 如果想让一个游

PMP项管2023年5月的备考准备攻略!

2023年共有4次PMP考试&#xff0c;分别是3月、5月、8月、11月&#xff0c;由于3月份考试不开放新报名&#xff0c;所以第一次备考PMP的同学可以选择参加5月份考试。那么&#xff0c;现在备考5月份PMP考试还来得及吗&#xff1f; 现在开始备考5月PMP考试&#xff0c;时间是非常…