多线程---阻塞队列+生产者消费者模型

文章目录

  • 阻塞队列
    • 自己实现一个阻塞队列(三步)
    • 标准库中的阻塞队列
    • 使用阻塞队列的优势
  • 生产者消费者模型

阻塞队列

队列(Queue)是我们熟悉的一个数据结构,它是“先进先出”的。但是并不是所有的队列都是“先进先出”的,比如:
优先级队列(PriorityQueue):基于自己的比较规则,拿出相应的值。
消息队列(MQ):在队列中引入一个“类型”,出队列的时候会指定某个类型的元素先出。

而我们今天学习的阻塞队列,它是一个“先进先出”的队列,但又有一些其他特点:

  1. 线程安全的。
  2. 带有阻塞功能:
    如果队列满,继续入队列,入队列操作就会阻塞,直到队列不满,入队列操作才能完成。
    如果队列空,继续出队列,出队列操作就会阻塞,直到队列不空,出队列操作才能完成。

自己实现一个阻塞队列(三步)

  • 实现基本队列
class MyBlockingQueue{
    public int[] items = new int[100];
    public int head = 0;
    public int tail = 0;
    public int size = 0;

    //入队列
    public void put ( int key)  {
            // 插入操作
            items[tail] = key;

            tail++;

            if (tail >= items.length) {
                tail = 0;
            }

            size++;
        
    }


    //出队列
    public Integer take()  {
            // 删除操作
            int ret = items[head];
            head++;

            if (head >= items.length) {
                head = 0;
            }

            size--;
            
            return ret;
        
    }
}

  • 保证线程安全
class MyBlockingQueue{
    public int[] items = new int[100];
    public int head = 0;
    public int tail = 0;
    public int size = 0;

    //入队列

    public void put ( int key)  {
        synchronized (this) {
            // 插入操作
            items[tail] = key;

            tail++;

            if (tail >= items.length) {
                tail = 0;
            }

            size++;
        }
    }


    //出队列
    public Integer take()  {
        synchronized (this) {
            // 删除操作
            int ret = items[head];
            head++;

            if (head >= items.length) {
                head = 0;
            }

            size--;
           
            return ret;
        }
    }
}

  • 实现阻塞功能
class MyBlockingQueue{
    public int[] items = new int[100];
    public int head = 0;
    public int tail = 0;
    public int size = 0;

    //入队列

    public void put ( int key) throws InterruptedException {
        synchronized (this) {


            //当wait被唤醒之后 size还有可能为满 所以不能一唤醒了就直接去使用 得再次判断条件是否满足
            // 比如:1.抛出异常  2. 三个线程同时执行 其中两个线程竞争锁 没竞争到锁的线程被唤醒之后size还为空
            while(size >= items.length){
                this.wait();
            }

            //判断队列是否为满  满了不能插入 就阻塞
//            if (size >= items.length){
//                this.wait();
//            }

            // 插入操作
            items[tail] = key;

            tail++;

            if (tail >= items.length) {
                tail = 0;
            }

            size++;
            this.notify();

        }
    }


    //出队列
    public Integer take() throws InterruptedException {
        synchronized (this) {

            //当wait被唤醒之后 size还有可能为空 所以不能一唤醒了就直接去使用 得再次判断条件是否满足
            while(size <= 0){
                this.wait();
            }
            //判断队列是否为空 空了不能删除 就阻塞
//            if (size <= 0){
//                this.wait();
//            }

            // 删除操作
            int ret = items[head];
            head++;

            if (head >= items.length) {
                head = 0;
            }

            size--;
            this.notify();
            return ret;
        }
    }
}

标准库中的阻塞队列

    //标准库的阻塞队列
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<Integer> blockingQueue = new LinkedBlockingDeque<>(2);
        //带有阻塞功能的入队列
        blockingQueue.put(1);
        blockingQueue.put(2);
        blockingQueue.take();
        blockingQueue.put(3);

        //带有阻塞功能的出队列
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());
        System.out.println(blockingQueue.take());

        blockingQueue.put(4);
        System.out.println(blockingQueue.take());

        blockingQueue.put(4);
    }

使用阻塞队列的优势

  • 有利于代码解耦合

在这里插入图片描述
在这里插入图片描述

  • 削峰填谷

在服务器A流量激增的情况下,通过阻塞队列能够进行限流。使服务器B、C、D能够不受干扰、平稳运行。

生产者消费者模型

生产者消费者模型:描述的是多线程协同工作的一种方式。借助阻塞队列实现。

	//生产者-消费者模型
    public static void main(String[] args) {
        MyBlockingQueue myBlockingQueue = new MyBlockingQueue();

        Thread thread = new Thread(() -> {
            int n = 1;
            while (true){
                try {
                    myBlockingQueue.put(n);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                n++;
            }
        });

        Thread thread1 = new Thread(() -> {
            while (true){
                try {
                    System.out.println(myBlockingQueue.take());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        thread.start();
        thread1.start();
    }

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

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

相关文章

RocketMq源码分析(八)--消息消费流程

文章目录 一、消息消费实现二、消息消费过程1、消息拉取2、消息消费1&#xff09;提交消费请求2&#xff09;消费消息 一、消息消费实现 消息消费有2种实现&#xff0c;分别为&#xff1a;并发消费实现&#xff08;ConsumeMessageConcurrentlyService&#xff09;和顺序消费实现…

pre-existing shared memory block

发生原因: 1.服务器cpu、内存进行扩容 2.非正常关闭,导致任在占用共享内存段 解决方案: 根据shmid进行关闭 ipcs -mipcrm -m xxx

Kotlin协程核心理解

一、协程是什么&#xff1f; 1.1 基本概念的理解 我们知道JVM中的线程的实现是依赖其运行的操作系统决定的&#xff0c;JVM只是在上层进行了API的封装&#xff0c;包含常见的有线程的启动方法&#xff0c;状态的管理&#xff0c;比如&#xff1a;Java中抽象出了6种状态&#x…

windows8080端口占用

查看端口占用 netstat -ano | findstr “8080”查看占用进程 tasklist | findstr “4664”关闭占用进程 taskkill /f /t /im httpd.exe

读图数据库实战笔记03_遍历

1. Gremlin Server只将数据存储在内存中 1.1. 如果停止Gremlin Server&#xff0c;将丢失数据库里的所有数据 2. 概念 2.1. 遍历&#xff08;动词&#xff09; 2.1.1. 当在图数据库中导航时&#xff0c;从顶点到边或从边到顶点的移动过程 2.1.2. 类似于在关系数据库中的查…

操作系统 --- 存储器管理

一、简答题 1.存储器管理的基本任务&#xff0c;是为多道程序的并发执行提供良好的存储器环境。请问好的存储器环境”应包含哪几个方面&#xff1f; 答&#xff1a; 2.内存保护是否可以完全由软件实现&#xff1f;为什么&#xff1f; 答&#xff1a;内存保护的主要任务是确保每…

C语言_断言assert详解

一、assert定义 assert() 的用法像是一种"契约式编程"&#xff0c;在我的理解中&#xff0c;其表达的意思就是&#xff0c;程序在我的假设条件下&#xff0c;能够正常良好的运作&#xff0c;其实就相当于一个 if 语句&#xff1a; if(假设成立) {程序正常运行&…

用户登录前后端开发(一个简单完整的小项目)——SpringBoot与session验证(带前后端源码)全方位全流程超详细教程

&#x1f9f8;注&#xff1a;不要看我的文件多&#xff0c;那是我的其他项目&#xff0c;这个项目所用的文件我会全部用红框框起来&#xff0c;没框的部分不用管&#xff0c;前端两个文件&#xff0c;后端一个文件 &#x1f4dc; 目录 首先&#xff0c;定义前后端交互接口 然…

强化学习中值函数应用示例

一、Gridworld Gridworld是一个用于教授强化学习概念的简化的电子游戏环境。它具有一个简单的二维网格&#xff0c;智能体可以在其中执行动作并获得奖励。这个环境是有限的&#xff0c;因为它有一个明确的开始和结束状态&#xff0c;以及一组确定的动作和奖励。 在Gridworld中&…

use renv with this project create a git repository

目录 1-create a git repository 2-Use renv with this project 今天在使用Rstudio过程中&#xff0c;发现有下面两个新选项&#xff08;1&#xff09;create a git repository (2) Use renv with this project. 选中这两个选项后&#xff0c;创建新项目&#xff0c;在项目目…

NEFU数字图像处理(三)图像分割

一、图像分割的基本概念 1.1专有名词 前景和背景 在图像分割中&#xff0c;我们通常需要将图像分为前景和背景两个部分。前景是指图像中我们感兴趣、要分割出来的部分&#xff0c;背景是指和前景不相关的部分。例如&#xff0c;对于一张人物照片&#xff0c;人物就是前景&…

目标检测算法改进系列之添加EIOU,SIOU,AlphaIOU,FocalEIOU等

YOLOv8添加EIoU,SIoU,AlphaIoU,FocalEIoU,Wise-IoU等 yolov8中box_iou其默认用的是CIoU&#xff0c;其中代码还带有GIoU&#xff0c;DIoU&#xff0c;文件路径&#xff1a;ultralytics/yolo/utils/metrics.py&#xff0c;函数名为&#xff1a;bbox_iou 原始代码 def bbox_i…

故障诊断模型 | Maltab实现LSTM长短期记忆神经网络故障诊断

文章目录 效果一览文章概述模型描述源码设计参考资料效果一览 文章概述 故障诊断模型 | Maltab实现LSTM长短期记忆神经网络故障诊断 模型描述 长短记忆神经网络——通常称作LSTM,是一种特殊的RNN,能够学习长的依赖关系。 他们由Hochreiter&Schmidhuber引入,并被许多人进行了…

2023 年值得关注的国外网络安全初创公司

网络安全初创公司试图解决的问题往往有点超前于主流。他们可以比大多数老牌公司更快地填补空白或新兴需求。初创公司通常可以更快地创新&#xff0c;因为它们不受安装基础的限制。 当然&#xff0c;缺点是初创公司往往缺乏资源和成熟度。公司致力于初创公司的产品或平台是有风…

基于单片机的空气质量检测系统

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 技术交流认准下方 CSDN 官方提供的联系方式 文章目录 概要 一、主要内容二、系统方案设计2.1 系统方案设计2.2 主控制器模块选择 三、 系统软件设计4.1 程序结构分析4.2系统程序…

基于SSM的会员卡管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

S32K144芯片焊接完成后使用S32DS初次下载无法下载解决方法

一、问题现象如下&#xff0c;S32DS Debug下报错 二、原因&#xff0c;原厂芯片出厂时的FLASH Memory的安全机制是激活的&#xff0c;仿真器是可以连上&#xff0c;但是没法读取Flash Memory的内容 三、解决方法 参考图示&#xff0c;解锁后即可正常Debug

Mac电脑配置Dart编程环境

1.安装Dart SDK 官网地址&#xff1a;https://dart.dev/get-dart $brew tap dart-lang/dart$brew install dart 安装后&#xff0c;用命令检测一下是否安装正常。 $brew info dart 2.VS Code配置Dart环境 1).安装VS Code 官网地址&#xff1a;https://code.visualstudio.c…

【技能树笔记】网络篇——练习题解析(十)

【技能树笔记】网络篇系列前九篇 【技能树笔记】网络篇——练习题解析&#xff08;一&#xff09;-CSDN博客 【技能树笔记】网络篇——练习题解析&#xff08;二&#xff09;-CSDN博客 【技能树笔记】网络篇——练习题解析&#xff08;三&#xff09;-CSDN博客 【技能树笔记】网…

DAY38 动态规划 + 509. 斐波那契数 + 70. 爬楼梯 + 746. 使用最小花费爬楼梯

动态规划理论 动态规划&#xff0c;Dynamic Programming&#xff0c; DP&#xff0c; 如果某一问题有很多重叠子问题&#xff0c;使用动态规划是最有效的。 所以动态规划中每一个状态一定是由上一个状态推导出来的&#xff0c;这一点就区分于贪心&#xff0c;贪心没有状态推导…