【多线程】阻塞队列 | put()方法 | take()方法 | 生产者-消费者模式 |实现阻塞队列

文章目录

    • 阻塞队列
      • 1.生产者-消费者模式
        • 生产者消费者模型的意义:
          • 1.解耦合
          • 2.削峰填谷:
      • 2.阻塞队列的使用
            • BlockingQueue
      • 3.实现阻塞队列
          • 唤醒:
          • 使用阻塞队列实现生产者消费者模型


阻塞队列

阻塞队列是一种特殊的队列:

  • 1.是线程安全的。

  • 2.带有阻塞特性

    如果队列为空,继续出队列,就会发生阻塞。直到其他线程往队列中添加队列为止

    如果队列为满,继续入队列, 也会发生阻塞,直到其他线程从队列中取走元素为止

阻塞队列可以来实现生产者-消费者模型。

1.生产者-消费者模式

生产者:把生产出来的内容,放到阻塞队列中。

消费者:从阻塞队列中获取内容。

生产者消费者模型的意义:
1.解耦合

两个模块联系越紧密,耦合就越高。对于分布式系统来说,更加有意义。

在这里插入图片描述

可以使用生产者-消费者模型,实现解耦合的效果。

在这里插入图片描述

2.削峰填谷:

峰:短时间内,请求量比较多时。

谷:请求量比较少时。

在这里插入图片描述

​ 在这种情况下:高峰时段,一旦客户端发起的请求量非常多时,每个A收到的请求,都会立即发给B。此时,A和B的访问量是相同的。但是在实际上,由于不同的服务器,上面跑的业务不同。虽然访问量一样,单个访问,消耗的硬件资源是不一样的。可能服务器A可以承担这些并发量,但是服务器B承担不了,就会挂掉。

在引入了生产者-消费者模型之后,就会解决这类问题。

在这里插入图片描述

  • 当服务器A收到了大量请求之后,A会把对应的请求写入到队列中。B仍然按照之前的节奏来处理请求。(削峰)
  • 一般情况下,峰值不会持续存在,峰值过后,A的请求量就会恢复正常、甚至减低。服务器B就可以在此时,逐渐把积压的请求给处理掉。(填谷)。

2.阻塞队列的使用

BlockingQueue

在这里插入图片描述

  • BlockingQueue是一个具体的接口,所以需要new一个具体的实现。

  • 同时BlockingQueue继承自Queue。也可以使用Queue的方法(没有阻塞属性)

    1.基于数组实现

    2.基于链表实现

  • BlockingQueue带有阻塞的方法:

    ​ put:阻塞式入队列

    ​ take:阻塞式出队列

    没有提供阻塞式获取队首元素的方法。

    public static void main(String[] args) {
       // BlockingQueue<String> queue = new ArrayBlockingQueue<>();
        BlockingQueue<String>queue = new LinkedBlockingQueue<>();
   
        queue.put("111");
        queue.put("222");
        queue.put("333");
        queue.put("444");
        String elem = queue.take();
        System.out.println(elem);
        elem = queue.take();
        System.out.println(elem);
        elem = queue.take();
        System.out.println(elem);
        elem = queue.take();
        System.out.println(elem);

    }

3.实现阻塞队列

给一个普通的队列加上线性安全和阻塞

对入队和出队的方法进行加锁。对数据的修改实现原子性操作,保证线程安全

  • put入队的时候,如果队列满了,就进行阻塞(wait)

在出队的时候,当size–后,队列中有位置了,调用notify()方法,对阻塞的put方法进行唤醒。

  • 同样的,如果take出队列时,队列为空的话,也需要进行阻塞。

在入队时,当size++后,队列不为空了,调用notify()方法,对阻塞的take方法进行唤醒。

在这里插入图片描述

  • 一个队列的阻塞情况,要么为空、要么为满。

    put和take只有一边能阻塞。如果put阻塞了,其他线程继续调用put,也会进行阻塞。只有靠take来唤醒。

    take阻塞,其他线程继续调用take也会进行阻塞,只能靠put来唤醒。

唤醒:

wait方法除了使用notify()方法进行唤醒,还可以通过interrupt()方法,来中断wait的状态。

使用interrupt方法唤醒的时候,会出现InterruptedException异常

public void put(String elem) throws InterruptedException {
    
}

因为是throws抛出的异常,执行到interrupt()方法后,整个方法就会结束。

    public void put(String elem) {
        synchronized (this) {
            if (size == data.length) {
                try {
                    this.wait();
                }catch (InterruptedException e){ 
                }
            }
            data[tail] = elem;
            tail++;
            if (tail == data.length) {
                tail = 0;
            }
            size++;
            this.notify();
        }
  • 如果是try-catch来处理异常。如果出现异常,程序仍会继续执行下去。在满队列的情况下。强行修改,会覆盖掉tail的值,并且size会超出数组长度。

​ 使用wait时,要考虑wait是notify唤醒的,还是通过Interrupt唤醒的。在wait返回时,还要进行判断wait执行的条件符不符合。可以直接将wait写在while循环中。循环的条件就是wait执行的条件。使wait在唤醒之后,再确定一下,条件是否满足。

            while (size == data.length) {
                //队列满了,就会进行堵塞
               this.wait();
            }
  • 最终再通过volatile修饰要频繁修改的变量,避免出现内存可见性问题。
class MyBlockingQueue {
    private String[] data = new String[1000];
    private  volatile int head = 0;
    //队列起始位置
    private volatile int tail = 0;
    //队列结束位置的下一个元素。
    private volatile int size = 0;
    //队列中有效元素个数

    //入队
    public void put(String elem) throws InterruptedException {

        synchronized (this) {
            while (size == data.length) {
                //队列满了,就会进行堵塞
               this.wait();
            }
            //队列没满,向队列添加元素
            data[tail] = elem;
            tail++;
            if (tail == data.length) {
                //满了之后,环形队列要回到开头。
                tail = 0;
            }
            size++;
            this.notify();
            //唤醒take中的wait
        }


    }

    //出队
    public String take() throws InterruptedException {
        synchronized (this) {
            while (size == 0) {
                //队列为空时
               this.wait();
            }
            //队列不空时,把队首head位置删除
            String ret = data[head];
            head++;
            if (head == data.length) {
                head = 0;
            }
            size--;
            this.notify();
            //唤醒put中的wait.
            return ret;
        }
    }
}

使用阻塞队列实现生产者消费者模型
    public static void main(String[] args) {
        MyBlockingQueue queue = new MyBlockingQueue();
        //消费者
        Thread t1 = new Thread(() -> {
            while (true){
                try {
                   String res =  queue.take();
                    System.out.println("消费元素: "+res);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

        });
        //生产者
        Thread t2 = new Thread(() -> {
            int num = 1;
            while (true){
                try {
                    queue.put(num+" ");
                    System.out.println("生产元素:"+num);
                    num++;

                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t1.start();
        t2.start();

    }

生产元素:1001
生产元素:1002
消费元素: 2 
消费元素: 3 
生产元素:1003
消费元素: 4 
生产元素:1004
  • 生产者快速生产了1000多个,消费者才消耗几个。队列填满之后,生产者进入了阻塞。直到消费者消费了之后,才会进行生产。消费一个生产一个。

点击移步博客主页,欢迎光临~

偷cyk的图

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

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

相关文章

视频自定义字幕,中英文,彩色的,你也可以,不会不知道吧

前言 关于【SSD系列】&#xff1a; 前端一些有意思的内容&#xff0c;旨在3-10分钟里&#xff0c;有所获&#xff0c;又不为所累。 字幕&#xff0c;大家见过吧&#xff0c;其实你也可以&#xff0c;真的可以&#xff0c;真的真的可以。不难&#xff0c;不难&#xff0c;真的…

leetcode1448.统计二叉树中的好节点数目

1. 题目描述 题目链接 2. 解题思路 首先看一下题目的“核心”&#xff0c;什么是好节点&#xff1a;从根到该节点 X 所经过的节点中&#xff0c;没有任何节点的值大于 X 的值。也就是说&#xff0c;我们只要知道了从根节点到该节点的所有的值&#xff0c;就可以判断该节点是…

优斯特:防静电包装解决方案的巧妙运用

在现代电子产品生产与运输领域&#xff0c;防静电包装已成为保障产品安全的必备环节。优斯特凭借其创新的防静电包装解决方案&#xff0c;为客户提供了一种巧妙的方式来确保产品在存储和运输过程中不受静电影响&#xff0c;并且不会被刮花或损坏。 静电对产品的影响 静电对电子…

数学建模--深入剖析线性规划(模型全方位解读+代码分析)

1.简介 &#xff08;1&#xff09;线性规划三要素 &#xff08;2&#xff09;模型适用赛题 2.典例讲解 &#xff08;1&#xff09;问题分析 目标函数是净收益尽可能大&#xff0c;风险尽可能小&#xff1b; 约束条件是交易费的分段函数&#xff0c;以及每一笔投资都是非负数&am…

java绘图在ubuntu报错

把JRT网站部署到ubuntu桌面系统上&#xff0c;开始没测试绘图部分功能&#xff0c;只试了连PostGreSql部分正常。后面试了生成位图部分发现报错。 报下面错误&#xff1a; (ColorModel.java:220)\n\tat java.desktop/java.awt.image.BufferedImage.(BufferedImage.java:286)\n…

阿赵UE学习笔记——28、粒子系统Niagara简介

阿赵UE学习笔记目录 大家好&#xff0c;我是阿赵。   继续学习虚幻引擎的使用。这次开始学习粒子系统的使用。 一、Cascade系统 在介绍UE5的Niagara系统之前&#xff0c;必须先介绍一下旧版本的粒子系统。   在UE4的时候&#xff0c;虚幻引擎的粒子系统叫做Cascade&#x…

【iOS】——SDWebImage源码学习

文章目录 一、SDWebIamge简介二、SDWebImage的调用流程SDWebImage源码分析1.UIImageViewWebCache层2.UIViewWebCache层3.SDWebManager层4.SDWebCache层5.SDWebImageDownloader层 一、SDWebIamge简介 SDWebImage是iOS中提供图片加载的第三方库&#xff0c;可以给UIKit框架中的控…

思维导图ai生成软件分享5款好用的!

思维导图ai生成软件分享5款好用的&#xff01; 在快节奏的信息时代&#xff0c;思维导图作为一种有效的思维整理工具&#xff0c;越来越受到人们的青睐。它能够将复杂的思维过程可视化&#xff0c;帮助我们更好地梳理思路、规划工作。近年来&#xff0c;随着人工智能技术的飞速…

整数运算超越存储单元表示范围:上溢出、下溢出、回绕

示例&#xff1a; /*** brief how about integer-underflow-overflow? show you here.* author wenxuanpei* email 15873152445163.com(query for any question here)*/ #define _CRT_SECURE_NO_WARNINGS//support c-library in Microsoft-Visual-Studio #include <std…

408数据结构,怎么练习算法大题?

其实考研的数据结构算法题是有得分技巧的 得分要点 会写结构定义&#xff08;没有就自己写上&#xff09;写清楚解题的算法思想描述清楚算法实现最后写出时间和空间复杂度 以上这四步是完成一道算法题的基本步骤&#xff0c;也是其中得分的主要地方就是后面两步。但是前面两…

java-spring 图灵 04

在Spring框架中&#xff0c;可以使用org.springframework.core.io.support.ResourcePatternResolver接口的resolveBasePackage方法来将指定的基础包解析为用于包搜索路径的模式规范。 例如&#xff0c;如果基础包是com.example.app&#xff0c;则可以使用resolveBasePackage方法…

【深度学习】【机器学习】用神经网络进行入侵检测,NSL-KDD数据集,基于机器学习(深度学习)判断网络入侵,网络攻击,流量异常【3】

之前用NSL-KDD数据集做入侵检测的项目是&#xff1a; 【1】https://qq742971636.blog.csdn.net/article/details/137082925 【2】https://qq742971636.blog.csdn.net/article/details/137170933 有人问我是不是可以改代码&#xff0c;我说可以。 训练 我将NSL_KDD_Final_1.i…

Open3D 无效点滤波(32)

Open3D 无效点滤波(32) 一、算法介绍二、算法实现1.代码2.效果一、算法介绍 这个算法的目标是从点云数据中去除无效的点,这些无效点可能是由于坐标值为无穷大(inf)或者不是数字(NaN)而产生的。这些无效点可能会导致后续处理步骤出现错误或异常,因此在处理点云数据时需…

品深茶创始人是谁?

据说&#xff0c;品深茶的创始人之前是一个程序员&#xff0c;他在软件行业工作十多年&#xff0c;由于常年熬夜加班再加上抽烟喝酒等不良习惯&#xff0c;导致在一次体检中被查出患上了肾癌&#xff0c;对他来说&#xff0c;期待的财务自由还没实现&#xff0c;身体就已经完蛋…

java(网络编程)

什么是网络编程? 在网络通信协议下&#xff0c;不同计算机上运行的程序&#xff0c;进行的数据传输。 应用场景&#xff1a;即时通信、网游对战、金融证券、国际贸易、邮件、等等 不管是什么场景&#xff0c;都是计算机跟计算机之间通过网络进行数据传输 Java中可以使用ja…

CSS基础:width,height尺寸属性详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。云桃桃&#xff0c;大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端工具”&#xff0c;可获取 Web…

vue脚手架CLI的简单使用

目录 初始化脚手架说明具体步骤模板项目的结构main.js入口文件app.vuemain.jsrender main.js 修改默认配置 初始化脚手架 说明 Vue 脚手架是 Vue 官方提供的标准化开发工具&#xff08;开发平台&#xff09;。最新的版本是 4.x。文档: https://cli.vuejs.org/zh/。 具体步骤 …

QFS [VLDB‘13] 论文阅读笔记

原论文&#xff1a;The Quantcast File System (VLDB’13) QFS简介及技术要点 QFS&#xff08;Quantcast File System&#xff09;是由Quantcast开发的一个高效、可扩展的分布式文件系统&#xff0c;旨在提供与Hadoop分布式文件系统&#xff08;HDFS&#xff09;兼容的替代方案…

allure2教程-1-环境搭建

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 自动化测试执行完成后我们需要展示给其他人看&#xff0c;这就要有自动化测试报告了。复杂的测试报告当然可以自己代码实现&#xff0c;但用pytest-html或allure基本也能满足我们生成测试报告的要求了。本小节介绍…

如何基于香橙派AIpro将开源框架模型转换为昇腾模型

在前面的介绍中&#xff0c;我们知道了如何基于香橙派AIpro开发AI推理应用&#xff0c;也大致了解到在推理之前&#xff0c;需要把原始网络模型 (可能是 PyTorch 的、TensorFlow&#xff0c;可能是Caffe的等等) 转换成 .om 模型&#xff0c;然后才能调用昇腾的aclmdlExecute 等…