多线程——阻塞队列

news2024/11/17 22:17:43

什么是阻塞队列

相比于一般的队列,有两个特点
1.线程安全
2.带有阻塞功能
1)队伍为空时,出队列就会出现阻塞,阻塞到其他线程入队列为止
2)队伍为满时,入队列就会出现阻塞,阻塞到其他线程出队列为止

常用于生产者消费者模型
在这里插入图片描述
作用:
1.解耦合
2.削峰填谷

使用阻塞队列

public class Test12 {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(100);
        queue.put("qqq");
        String elem = queue.take();
        System.out.println("elem = "+ elem);
        elem = queue.take();
        System.out.println("elem = " + elem);

    }
}

运行结果
在这里插入图片描述
不会结束运行,一直在等待。

使用put和offer一样的都是入队列,但是put是带有阻塞功能,offer没有带阻塞功能(队满了就会返回结果)
take方法用来出队列,也是带有阻塞功能

实现阻塞队列

1)实现普通队列

class MyBlockingQueue{
    private String[] elems = null;
    private int size = 0;
    private int head = 0;
    private int tail = 0;
   
    public MyBlockingQueue(int capacity){
        elems = new String[capacity];
    }
    public void put(String elem) throws InterruptedException {
        
            if (size > elems.length){
                //阻塞功能
            }
            elems[tail] = elem;
            tail++;
            if (tail >= elems.length){
                tail = 0;
            }
            size++;
            
        

    }
    public String take() throws InterruptedException {
        
            if (size == 0){
                //阻塞功能
            }
            String elem = null;
            elem = elems[head];
            head++;
            if (head >= elems.length){
                head = 0;
            }
            size--;
           
            return elem;
        }
    }

}

2)加上线程安全

class MyBlockingQueue{
    private String[] elems = null;
    private int size = 0;
    private int head = 0;
    private int tail = 0;
    private Object locker = new Object();
    public MyBlockingQueue(int capacity){
        elems = new String[capacity];
    }
    public void put(String elem) throws InterruptedException {
        synchronized(locker){
            if (size > elems.length){
                
            }
            elems[tail] = elem;
            tail++;
            if (tail >= elems.length){
                tail = 0;
            }
            size++;
            
        }

    }
    public String take() throws InterruptedException {
        synchronized(locker){
            if (size == 0){
               
            }
            String elem = null;
            elem = elems[head];
            head++;
            if (head >= elems.length){
                head = 0;
            }
            size--;
           
            return elem;
        }
    }

}

3)加上阻塞功能

class MyBlockingQueue{
    private String[] elems = null;
    private int size = 0;
    private int head = 0;
    private int tail = 0;
    private Object locker = new Object();
    public MyBlockingQueue(int capacity){
        elems = new String[capacity];
    }
    public void put(String elem) throws InterruptedException {
        synchronized(locker){
            while (size > elems.length){
                locker.wait();
            }
            elems[tail] = elem;
            tail++;
            if (tail >= elems.length){
                tail = 0;
            }
            size++;
            locker.notify();
        }

    }
    public String take() throws InterruptedException {
        synchronized(locker){
            while (size == 0){
                locker.wait();
            }
            String elem = null;
            elem = elems[head];
            head++;
            if (head >= elems.length){
                head = 0;
            }
            size--;
            locker.notify();
            return elem;
        }
    }

}

代码解释:
最终代码将if改成了while,因为if只能判定一次,如果出现以下情况就会出bug(线程A,线程B都执行到了put中的wait,因为队列已满而停止运行,线程C出队列唤醒了线程A,线程A继续入队列,入队列后就会notify,导致唤醒了线程B,而此时队列已满,无法进行入队操作,就出现了bug),所以就使用while,wait之前判定一次,唤醒之后再进行一次判定,相当于多做一步确定操作

简单的生产者消费者模型

class MyBlockingQueue{
    private String[] elems = null;
    private int size = 0;
    private int head = 0;
    private int tail = 0;
    private Object locker = new Object();
    public MyBlockingQueue(int capacity){
        elems = new String[capacity];
    }
    public void put(String elem) throws InterruptedException {
        synchronized(locker){
            while (size > elems.length){
                locker.wait();
            }
            elems[tail] = elem;
            tail++;
            if (tail >= elems.length){
                tail = 0;
            }
            size++;
            locker.notify();
        }

    }
    public String take() throws InterruptedException {
        synchronized(locker){
            while (size == 0){
                locker.wait();
            }
            String elem = null;
            elem = elems[head];
            head++;
            if (head >= elems.length){
                head = 0;
            }
            size--;
            locker.notify();
            return elem;
        }
    }

}
public class Test11 {
    public static void main(String[] args) throws InterruptedException {
        MyBlockingQueue myBlockingQueue = new MyBlockingQueue(100);
        Thread t1 = new Thread(()->{
            int n = 1;
            while(true){
                try {
                    myBlockingQueue.put(n + "");
                    System.out.println("生产元素 "+n);
                    n++;
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

            }
        });
        Thread t2 = new Thread(()->{
           while(true){
               try {
                   String n = myBlockingQueue.take();
                   System.out.println("消费元素 " + n);
                   Thread.sleep(500);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }

        });
        t1.start();
        t2.start();
    }
}

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

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

相关文章

pandas查看数据常用方法(以excel为例)

目录 1.查看指定行数的数据head() 2. 查看数据表头columns 3.查看索引index 4.指定索引列index_col 5.按照索引排序 6.按照数据列排序sort_values() 7.查看每列数据类型dtypes 8.查看指定行列数据loc 9.查看数据是否为空isnull() 1.查看指定行数的数据head() &#xff…

【教3妹学编程-算法题】最大频率元素计数

2哥 : 3妹&#xff0c;最近有个电视剧《繁花》非常火&#x1f525;&#xff0c;你听说了吗&#xff1f; 3妹&#xff1a;没有&#xff0c;最近一直在忙着找工作&#xff0c;哪有时间看电视啊 2哥 : 啊&#xff1f;大周末还不休息一下啊&#xff0c;这么辛苦。 3妹&#xff1a;当…

CAN/CANFD数据记录仪汽车电子售后神器

CAN数据记录仪是一种用于采集和存储CAN总线数据的工具&#xff0c;广泛应用于汽车、轨道车辆、工业控制等大数据量且不易排查故障的系统中。它可以实时存储总线上的数据&#xff0c;方便后续的研究和分析。解决工程师售后难点。 在选择CAN数据记录仪时&#xff0c;需要根据实…

Jenkins-自动化

定时构建 使用Cron表达式指定执行时间。 # 格式 # ┌──分&#xff08;0 - 59&#xff09; # │ ┌──时&#xff08;0 - 23&#xff09; # │ │ ┌──日&#xff08;1 - 31&#xff09; # │ │ │ ┌─月&#xff08;1 - 12&#xff09; # │ │ │ │ ┌─星期&#…

CSC8021_computer network_The Application Layer

The Role of the Application layer The Application layer is the interface between the network and its users › It contains network services (e.g. DNS) › It contains user applications (e.g. email, web browsing&#xff09; Domain Name System (DNS) › The …

python 字符串的详细处理方法

当前版本&#xff1a; Python 3.8.4 简介 字符串是由字符组成的序列&#xff0c;可以用单引号、双引号或三引号&#xff08;单引号或双引号的连续使用&#xff09;括起来。一般用来表示和处理文本信息&#xff0c;可以是字母、数字、标点符号以及其他特殊字符&#xff0c;用于…

将PDF发票转换为excel、xml结构化数据的完美解决方案

随着电子发票的普及&#xff0c;越来越多的企业和个人开始使用PDF格式的电子发票。然而&#xff0c;有时我们需要将电子发票转换为XML格式以便于处理和分析。本文将介绍如何将收到的PDF发票下载为excel、xml文件。首先&#xff0c;我们需要明确一点&#xff0c;PDF是一种基于图…

微服务概述之微服务特性

前言 既然系统采用了微服务架构&#xff0c;就需要了解一些微服务的特性&#xff0c;这样在进行微服务开发时&#xff0c;脑海中才会有一些指导方向。微服务具有以下特性。 1. 服务组件化 组件是独立、可替换、可升级的软件的单元。将整体应用拆分成独立的服务组件后&#xff…

【算法分析与设计】和为k的子数组

目录 问题 示例 方案一&#xff1a; 思路&#xff1a; 算法设计 代码实现 运行结果&#xff1a; 方案二(调优) 思路&#xff08;前缀和&#xff09; 算法设计 示意图 代码实现 运行结果 问题 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数…

Python提取PDF中部分页面的实战代码

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

【小沐学GIS】基于OpenSceneGraph(OSG)绘制三维数字地球Earth

&#x1f37a;三维数字地球系列相关文章如下&#x1f37a;&#xff1a;1【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第一期2【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第二期3【小沐学GIS】…

CSS 一行三列布局,可换行(含grid网格布局、flex弹性布局/inline-block布局 + 伪类选择器)

效果 一、HTML <div class"num-wrap"><div class"num-item" v-for"num in 8" :key"num">{{ num }}</div></div> 二、CSS 1、grid网格布局&#xff08;推荐&#xff09; .num-wrap {// grid网格布局display…

Python轻松实现炫酷的手势检测

大家好&#xff0c;今天分享一个非常有意思且十分简单的python库——mediapipe库。该库集成了大量的深度学习模型&#xff0c;短短几行代码&#xff0c;就可以快速实现一个炫酷的实例&#xff0c;本文就以手势检测为例&#xff0c;展示一下这个强大的开源库。 mediapipe由Goog…

书生·浦语大模型实战营作业(四)

基础作业&#xff1a; 构建数据集&#xff0c;使用 XTuner 微调 InternLM-Chat-7B 模型, 让模型学习到它是你的智能小助手&#xff0c;效果如下图所示&#xff0c;本作业训练出来的模型的输出需要将不要葱姜蒜大佬替换成自己名字或昵称&#xff01; 数据集 回答结果 进阶作…

抽象类--java学习笔记

什麽是抽象类&#xff1f; 在java中有一个关键字叫&#xff1a;abstract&#xff0c;它就是抽象的意思&#xff0c;可以用它修饰类、成员方法abstract修饰类&#xff0c;这个类就是抽象类&#xff1b;修饰方法&#xff0c;这个方法就是抽象方法 认识抽象类 抽象类的注意事项…

2024.1.15每日一题

LeetCode 82.删除排序链表中的重复元素 II 82. 删除排序链表中的重复元素 II - 力扣&#xff08;LeetCode&#xff09; 题目描述 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 示例…

Mac M1 Parallels CentOS7.9 Rancher + K8S + Gitlab + Jenkins +Harbor CICD

一、资源清单 机器名称IP地址角色k8srancher高可用部署: https://blog.csdn.net/qq_41594280/article/details/135312148rancher10.211.55.200管理K8S集群k8svip10.211.55.199K8S VIPmaster0110.211.55.201K8S集群主节点master0210.211.55.202K8S集群主节点master0310.211.55.…

AC修炼计划(AtCoder Beginner Contest 335)E-F

传送门&#xff1a; AtCoder Beginner Contest 335 (Sponsored by Mynavi) - AtCoder A&#xff0c;B&#xff0c;C&#xff0c;D还算比较基础&#xff0c;没有什么思路&#xff0c;纯暴力就可以过。 这里来总结一下E和F E - Non-Decreasing Colorful Path 最开始以为是树形…

JVM:从零到入门

JVM&#xff0c;就是Java虚拟机。 JVM是一个巨大的话题&#xff0c;我们本文主要简单介绍一些围绕JVM相关的基础知识。 目录 JVM内存区域划分 本地方法栈 虚拟机栈 堆 程序计数器 方法区/ 元数据区 类加载 1.加载 2.验证 3.准备 4.解析 5.初始化 双亲委派模型 …

任务7:安装MySQL数据库

任务描述 知识点&#xff1a; MySQL数据库安装与使用 重 点&#xff1a; 基于CentOS系统&#xff0c;安装MySQL数据库 内 容&#xff1a; 安装MySQL数据库修改root用户密码 任务指导 MySQL是一个关系型数据库管理系统&#xff0c;由瑞典MySQL AB 公司开发&#xff0c…