认识阻塞队列

news2024/11/25 12:59:31

认识阻塞队列

  • 一、相关概念
    • 1.1 阻塞队列是什么
    • 1.2 生产者消费者模型
  • 二、标准库中的阻塞队列
    • 2.1 使用
    • 2.2 生产者消费者模型实现
  • 三、实现阻塞队列
    • 3.1 循环队列
    • 3.2 实现的细节
    • 3.3 代码

一、相关概念

1.1 阻塞队列是什么

阻塞队列是一种特殊的队列,也遵守 “先进先出” 的原则。

1)是一种线程安全的数据结构;
2)带有阻塞功能:

  • 当队列满的时候, 继续入队列就会阻塞,直到有其他线程从队列中取走元素;
  • 当队列空的时候, 继续出队列也会阻塞,直到有其他线程往队列中插入元素。

阻塞队列的一个典型应用场景就是 “生产者消费者模型”,这是一种非常典型的开发模型!

1.2 生产者消费者模型

生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。
生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取。

1)阻塞队列能使生产者和消费者之间解耦合!

比如过年一家人一起包饺子,一般都是有明确分工,比如一个人负责擀饺子皮,其他人负责包,擀饺子皮的人就是 “生产者”,包饺子的人就是 “消费者”。
擀饺子皮的人不关心包饺子的人是谁 (能包就行,无论是手工包,借助工具,还是机器包),包饺子的人也不关心擀饺子皮的人是谁 (有饺子皮就行,无论是用擀面杖擀的,还是拿罐头瓶擀,还是直接从超市买的)。

2)阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力!削峰填谷!

比如在 “秒杀” 场景下,服务器同一时刻可能会收到大量的支付请求。如果直接处理这些支付请求,服务器可能扛不住 (每个支付请求的处理都需要比较复杂的流程)。这个时候就可以把这些请求都放到一个阻塞队列中,然后再由消费者线程慢慢的来处理每个支付请求。这样做可以有效进行 “削峰”,防止服务器被突然到来的一波请求直接冲垮。
比如三峡大坝:
在这里插入图片描述

二、标准库中的阻塞队列

2.1 使用

在 Java 标准库中内置了阻塞队列。如果我们需要在一些程序中使用阻塞队列,直接使用标准库中的即可:

  • BlockingQueue 是一个接口,真正实现的类是 LinkedBlockingQueue、ArrayBlockingQueue等…
  • put 方法用于阻塞式的入队列,take 用于阻塞式的出队列
  • BlockingQueue 也有 offer、poll、peek 等方法,但是这些方法不带有阻塞特性
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<>(100);

        // 带有阻塞功能的入队列
        blockingQueue.put(1);
        blockingQueue.put(2);
        blockingQueue.put(3);

        Integer ret = blockingQueue.take();
        System.out.println(ret);
        ret = blockingQueue.take();
        System.out.println(ret);
        ret = blockingQueue.take();
        System.out.println(ret);


        ret = blockingQueue.take();
        System.out.println(ret);
    }
}

注意: 阻塞队列没有提供"带有阻塞的"取队首元素的功能,所以需要先take取出判断,不符合再重新put进队列!

2.2 生产者消费者模型实现

public static void main(String[] args) throws InterruptedException {
    BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<Integer>();
    Thread customer = new Thread(() -> {
        while (true) {
            try {
                int value = blockingQueue.take();
                System.out.println("消费元素: " + value);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, "消费者");
    customer.start();
    Thread producer = new Thread(() -> {
        Random random = new Random();
        while (true) {
            try {
                int num = random.nextInt(1000);
                System.out.println("生产元素: " + num);
                blockingQueue.put(num);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, "生产者");
    producer.start();
    customer.join();
    producer.join();
}

三、实现阻塞队列

3.1 循环队列

我们来基于数据实现:循环队列!
在这里插入图片描述
怎样区别"空"还是"满"?
1)浪费一个数组空间;2)添加计数器

循环队列更多内容~~请点击

3.2 实现的细节

保证线程安全,关键就是加锁!
实现阻塞:
1.如果队列为空,出队列就阻塞;
2.如果队列为满,入队列就阻塞。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
即使没有t3这一手,还有interrupt,也是有影响~~
所以,使用while是稳妥的写法!!!

3.3 代码

// 名字还是不要和标准库的混淆
class MyBlockingQueue {
    private int[] items = new int[1000];
    private volatile int head = 0;
    private volatile int tail = 0;
    private volatile int size = 0;

    // 入队列
    public void put(int elem) throws InterruptedException {
        synchronized (this) {
            // 判定队列是否满了, 满了则不能插入.
            while (size >= items.length) {
                this.wait();
            }
            // 进行插入操作, 把 elem 放到 items 里, 放到 tail 指向的位置.
            items[tail] = elem;
            tail++;
            if (tail >= items.length) {
                tail = 0;
            }
            size++;
            this.notify();
        }
    }

    // 出队列, 返回删除的元素内容
    public Integer take() throws InterruptedException {
        synchronized (this) {
            // 判定队列是否空, 如果空了, 则不能出队列
            while (size == 0) {
                this.wait();
            }
            // 进行取元素操作.
            int ret = items[head];
            head++;
            if (head >= items.length) {
                head = 0;
            }
            size--;
            this.notify();
            return ret;
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        MyBlockingQueue queue = new MyBlockingQueue();

        Thread producer = new Thread(() -> {
            int n = 1;
            while (true) {
                try {
                    queue.put(n);
                    System.out.println("生产元素 " + n);
                    n++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread customer = new Thread(() -> {
            while (true) {
                try {
                    int n = queue.take();
                    System.out.println("消费元素 " + n);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        producer.start();
        customer.start();
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CENTOS上的网络安全工具(十六)容器特色的Linux操作

这一篇&#xff0c;我们继续在Docker上折腾。之前我们已经展示了如何在容器上搭建安全产品的部署环境&#xff0c;这里我们需要更进一步&#xff0c;讨论如何在容器上搭建开发与调试环境。这是学习安全产品并且自己构建安全产品的基础步骤。 〇、精简系统上的操作技巧 使用Dock…

【LeetCode】直线上最多的点数 [H](几何)

149. 直线上最多的点数 - 力扣&#xff08;LeetCode&#xff09; 一、题目 给你一个数组 points &#xff0c;其中 points[i] [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。 示例 1&#xff1a; 输入&#xff1a;points [[1,1],[2,2],[3,3]] 输出&a…

【数据结构与算法分析】0基础带你学数据结构与算法分析11--AVL树

目录 二分查找 AVL 树 AVL 的平衡因子 AVL 的插入操作 单旋转 双旋转 对 AVL 树插入的总结 AVL 的移除操作 如果给定一个序列&#xff0c;你将如何在这个序列中查找一个给定元素 target&#xff0c;当找到时返回该元素的迭代器&#xff0c;否则返回末尾迭代器。首先排除…

python基于flask搭建http服务(二)—— 实现Excel上传、数据清洗、入库

一、技术点 利用flask 搭建简易的http服务,实现服务端文件上传;利用Blueprint将不同业务拆分至不同文件;利用bootstrap-fileinput组件构建页面;利用flask_cors配置允许跨域请求;利用sqlalchemy实现数据库连接;利用pandas实现Excel读取、清洗、入库;二、具体实现 2.1 目…

基于intel i3/i5/i7 视觉控制器 4个POE GigE

XM-5143 是针对机器视觉行业GigE相机应用场景的一款高性能工业计算机&#xff0c;可使用Intel 6/7代 65W 高性能CPU应对快速检测。4路独立Intel网络芯片&#xff0c;并支持POE供电&#xff0c;可减少布线。并配有快速隔离可编程DI/O芯片. XM-5143的规格产品类型机器视觉控制器防…

分布式事务都有哪些,到底有什么用,在项目当中该用哪个?

分布式的CAP理论应该是人尽皆知了&#xff0c;它描述了一致性&#xff08;C&#xff09;、可用性&#xff08;A&#xff09;、分区容错性&#xff08;P&#xff09;的一系列权衡。很多时候&#xff0c;我们要在一致性和可用性之间权衡&#xff0c;而分布式事务&#xff0c;就是…

20.EC实战 笔记本电脑的休眠唤醒是如何实现的

文章目录 1. EC什么时候(收到什么命令)之后来执行S0-->S3下电时序?2. S3(休眠)状态应该保留哪些电源?3. 控制笔记本进入休眠状态的三种方式总结:前言: 最近很多朋友在咨询休眠唤醒的问题,在笔记本中,休眠唤醒是一个基本功能,如果连休眠唤醒都没有,就失去了笔记本…

Volatile内存语义以及如何正确使用

目录 语义描述 重排序规则 JMM如何实现volatile语义 如何正确使用volatile变量 语义描述 写语义&#xff1a;当写一个volatile变量时候&#xff0c;JMM会把该线程对应的本地内存的共享变量直接刷新到主内存中。 读语义&#xff1a;当读一个volatile变量的时候。JMM会把该线…

分布式锁主动续期的入门级实现-自省 | 简约而不简单

一、背景 如果某个客户端获得锁之后处理时间超过最大约定时间&#xff0c;或者持锁期间内发生了故障导致无法主动释放锁&#xff0c;其持有的锁也能够被其他机制正确释放&#xff0c;并保证后续其它客户端也能加锁&#xff0c;整个处理流程继续正常执行。 简单解释一下&#xf…

LLeetCode题目笔记——6258. 数组中最长的方波

文章目录题目描述题目难度——中等方法一&#xff1a;一次遍历哈希代码Python暴力代码Python一次遍历总结题目描述 这是这周周赛的第二题&#xff0c;本来想是不是双指针的解法&#xff0c;但想半天没想出来咋用双指针&#xff0c;就想到了哈希。 给你一个整数数组 nums 。如果…

PostgreSQL数据库TPCC测试,Banchmarksql 5.0部署详解

1 BenchmarkSQL安装部署 1.1 部署Java环境 首先使用java - version查看是否已有 Java环境&#xff08;下图是有的情况&#xff09; 需要注意的是&#xff0c;虚拟机中默认的JDK貌似是不行的哦&#xff0c;请参考下面链接中的博文&#xff0c;教你怎么卸载重装 1.1.1 若没有J…

Python学习基础笔记四十四——模块1

1、看一个例子&#xff1a; 创建一个demo.py文件&#xff1a; print(in demo.py)def hello():print(in hello function) 然后我们在另外一个文件中import这个demo文件&#xff1a; import demo# 调用demo.py文件中的hello()函数 demo.hello() 注意&#xff0c;demo后面没有…

软件安全测试-BurpSuite使用详解

1.BurpSuite简介 Burp Suite 是用于攻击web 应用程序的集成平台&#xff0c;它包含了许多Burp工具&#xff0c;这些不同的burp工具通过协同工作&#xff0c;有效的分享信息&#xff0c;支持以某种工具中的信息为基础供另一种工具使用的方式发起攻击。 它主要用来做安全性渗透测…

我将 9 个 ChatGPT 账号接入微信,我现在整个人都麻了...

大家好&#xff0c;我是米开朗基杨。最近大家都被 ChatGPT 刷屏了&#xff0c;这家伙真是上天入地无所不能&#xff0c;不管什么问题都能解答&#xff0c;而且答案的质量非常高&#xff0c;完全不像机器人。于是乎我冒出个想法&#xff1a;如果把 ChatGPT 接入微信是什么感觉&a…

二维码介绍

二维码介绍 二维码&#xff08;2-dimensional bar code、二维条码&#xff09;是用某种特定的几何图形按一定规律在平面&#xff08;二维方向上&#xff09;分布的、黑白相间的、记录数据符号信息的图形&#xff1b;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1…

repo的安装和使用

前言 Android 采用 Gerrit 提供代码评审服务&#xff0c;并且开发了一个客户端工具 repo&#xff0c;实现多仓库管理。Git 的开发者对服务端的 Git 源码做了扩展&#xff0c;使得基于 Git&#xff08;cgit&#xff09;的代码平台可以很容易引入新的集中式工作流。同样 git-rep…

概率统计·参数估计【矩估计、极大似然估计、无偏性、有效性、相合性】

点估计 设总体的分布函数形式已知&#xff0c;但它的一个或多个参数为未知&#xff0c;借助于总体的一个样本来估计总体未知参数的值的问题称为点估计问题 矩估计 这个还是看例子会比较好理解一些 例 先μ1E(x)&#xff0c;μ2E(x2)有几个未知参数就列几次方的期望&#xff…

CSS -- 01. CSS基础

文章目录CSS基础1 CSS简介1.1 HTML的局限性1.2 CSS介绍1.3 CSS语法规范1.4 CSS代码风格2 CSS基础选择器2.1 选择器的分类2.2 标签选择器2.3 **类选择器**2.4 id选择器2.5 通配符选择器2.6 基础选择器总结3 CSS字体属性3.1 字体系列3.2 字体大小3.3 字体粗细3.4 文字样式3.5 字体…

[附源码]JAVA毕业设计医药垃圾分类管理系统(系统+LW)

[附源码]JAVA毕业设计医药垃圾分类管理系统&#xff08;系统LW&#xff09; 项目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目…

Day827.安全性、活跃性以及性能问题 -Java 并发编程实战

安全性、活跃性以及性能问题 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于安全性、活跃性以及性能问题的内容。 并发编程中需要注意的问题有很多&#xff0c;主要有三个方面&#xff0c;分别是&#xff1a; 安全性问题活跃性问题性能问题 一、安全性问题 相信一…