0

0

分析Java中阻塞队列的示例

PHPz

PHPz

发布时间:2023-05-09 21:43:06

|

1554人浏览过

|

来源于亿速云

转载

    1. 什么是阻塞队列

     阻塞队列是一种特殊的队列,和数据结构中普通的队列一样,也遵守先进先出的原则同时,阻塞队列是一种能保证线程安全的数据结构,并且具有以下两种特性:当队列满的时候,继续向队列中插入元素就会让队列阻塞,直到有其他线程从队列中取走元素;当队列为空的时候,继续出队列也会让队列阻塞,直到有其他线程往队列中插入元素

    补充:线程阻塞的意思指代码此时不会被执行,即操作系统在此时不会把这个线程调度到CPU上去执行了

    2. 阻塞队列的代码使用

    import java.util.concurrent.LinkedBlockingDeque;
    import java.util.concurrent.BlockingDeque;
    public class Test {
        public static void main(String[] args) throws InterruptedException {
            //不能直接newBlockingDeque,因为它是一个接口,要向上转型
            //LinkedBlockingDeque内部是基于链表方式来实现的
            BlockingDeque<String> queue=new LinkedBlockingDeque<>(10);//此处可以指定一个具体的数字,这里的的10代表队列的最大容量
            queue.put("hello");
            String elem=queue.take();
            System.out.println(elem);
            elem=queue.take();
            System.out.println(elem);
        }
    }

    注意: put方法带有阻塞功能,但是offer不具有,所以一般用put方法(能使用offer方法的原因是 BlockingDeque继承了Queue

    Java中阻塞队列的示例分析


    打印结果如上所示,当打印了hello后,队列为空,代码执行到elem=queue.take();就不会继续往下执行了,此时线程进入阻塞等待状态,什么也不会打印了,直到有其他线程给队列中放入新的元素为止

    立即学习Java免费学习笔记(深入)”;

    3. 生产者消费者模型

    生产者消费者模型是在服务器开发和后端开发中比较常用的编程手段,一般用于解耦合和削峰填谷。

    高耦合度:两个代码模块的关联关系比较高
    高内聚:一个代码模块内各个元素彼此结合的紧密
    因此,我们一般追求高内聚低耦合,这样会加快执行效率,而使用生产者消费者模型就可以解耦合

    (1)应用一:解耦合

    我们以实际生活中的情况为例,这里有两台服务器:A服务器和B服务器,当A服务器传输数据给B时,要是直接传输的话,那么不是A向B推送数据,就是B从A中拉取数据,都是需要A和B直接交互,所以A和B存在依赖关系(A和B的耦合度比较高)。未来如果服务器需要扩展,比如加一个C服务器,让A给C传数据,那么改动就比较复杂,且会降低效率。这时我们可以加一个队列,这个队列为阻塞队列,如果A把数据写到队列里,B从中取,那么队列相当于是中转站(或者说交易场所),A相当于生产者(提供数据),B相当于消费者(接收数据),此时就构成了生产者消费者模型,这样会让代码耦合度更低,维护更方便,执行效率更高。

    Java中阻塞队列的示例分析

    在计算机中,生产者充当其中一组线程,而消费者充当另一组线程,而交易场所就可以使用阻塞队列了

    (2)应用二:削峰填谷

    Java中阻塞队列的示例分析

    实际生活中
    在河道中大坝算是一个很重要的组成部分了,如果没有大坝,大家试想一下结果:当汛期来临后上游的水很大时,下游就会涌入大量的水发生水灾让庄稼被淹没;而旱期的话下游的水会很少可能会引发旱灾。若有大坝的话,汛期时大坝把多余的水存到大坝中,关闸蓄水,让上游的水按一定速率往下流,避免突然一波大雨把下游淹了,这样下游不至于出现水灾。旱期时大坝把之前储存好的水放出来,还是让让水按一定速率往下流,避免下流太缺水,这样既可以避免汛期发生洪涝又可以避免旱期发生旱灾了。
    峰:相当于汛期
    谷:相当于旱期
    计算机中
    这样的情况在计算机中也是很典型的,尤其是在服务器开发中,网关通常会把互联网中的请求转发给业务服务器,比如一些商品服务器,用户服务器,商家服务器(存放商家的信息),直播服务器。但因为互联网过来的请求数量是多是少不可控,相当于上游的水,如果突然来了一大波请求,网关即使能扛得住,后续的很多服务器收到很多请求也就会崩溃(处理一个请求涉及到一系列的数据库操作,因为数据库相关操作效率本身比较低,这样请求多了就处理不过来了,因此就会崩溃)

    Java中阻塞队列的示例分析

    听脑AI
    听脑AI

    听脑AI语音,一款专注于音视频内容的工作学习助手,为用户提供便捷的音视频内容记录、整理与分析功能。

    下载

    所以实际情况中网关和业务服务器之间往往用一个队列来缓冲,这个队列就是阻塞队列(交易场所),用这个队列来实现生产者(网关)消费者(业务服务器)模型,把请求缓存到队列中,后面的消费者(业务服务器)按照自己固定的速率去读请求。这样当请求很多时,虽然队列服务器可能会稍微受到一定压力,但能保证业务服务器的安全。

    (3)相关代码

    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    
    public class TestDemo {
        public static void main(String[] args) {
            // 使用一个 BlockingQueue 作为交易场所
            BlockingQueue<Integer> queue = new LinkedBlockingQueue<>();
            // 此线程作为消费者
            Thread customer = new Thread() {
                @Override
                public void run() {
                    while (true) {
                        // 取队首元素
                        try {
                            Integer value = queue.take();
                            System.out.println("消费元素: " + value);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            customer.start();
            // 此线程作为生产者
            Thread producer = new Thread() {
                @Override
                public void run() {
                    for (int i = 1; i <= 10000; i++) {
                        System.out.println("生产了元素: " + i);
                        try {
                            queue.put(i);
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            producer.start();
            try {
                customer.join();
                producer.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    Java中阻塞队列的示例分析

    打印如上(此代码是让生产者通过sleep每过1秒生产一个元素,而消费者不使用sleep,所以每当生产一个元素时,消费者都会立马消费一个元素)

    4.阻塞队列和生产者消费者模型功能的实现

    在学会如何使用BlockingQueue后,那么如何自己去实现一个呢?
    主要思路:

    • 1.利用数组

    • 2.head代表队头,tail代表队尾

    • 3.head和tail重合后到底是空的还是满的判断方法:专门定义一个size记录当前队列元素个数,入队列时size加1出队列时size减1,当size为0表示空,为数组最大长度就是满的(也可以浪费一个数组空间用head和tail重合表示空,用tail+1和head重合表示满,但此方法较为麻烦,上一个方法较为直观,因此我们使用上一个方法)

    public class Test2 {
        static class BlockingQueue {
        private int[] items = new int[1000];    // 此处的1000相当于队列的最大容量, 此处暂时不考虑扩容的问题.
        private int head = 0;//定义队头
        private int tail = 0;//定义队尾
        private int size = 0;//数组大小
        private Object locker = new Object();
    
        // put 用来入队列
        public void put(int item) throws InterruptedException {
            synchronized (locker) {
                while (size == items.length) {
                    // 队列已经满了,阻塞队列开始阻塞
                    locker.wait();
                }
                items[tail] = item;
                tail++;
                // 如果到达末尾, 就回到起始位置.
                if (tail >= items.length) {
                    tail = 0;
                }
                size++;
                locker.notify();
            }
        }
        // take 用来出队列
        public int take() throws InterruptedException {
            int ret = 0;
            synchronized (locker) {
                while (size == 0) {
                    // 对于阻塞队列来说, 如果队列为空, 再尝试取元素, 就要阻塞
                    locker.wait();
                }
                ret = items[head];
                head++;
                if (head >= items.length) {
                    head = 0;
                }
                size--;
                // 此处的notify 用来唤醒 put 中的 wait
                locker.notify();
            }
            return ret;
        }
    }
    
        public static void main(String[] args) throws InterruptedException {
            BlockingQueue queue = new BlockingQueue();
            // 消费者线程
            Thread consumer = new Thread() {
                @Override
                public void run() {
                    while (true) {
                        try {
                            int elem = queue.take();
                            System.out.println("消费元素: " + elem);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            consumer.start();
    
            // 生产者线程
            Thread producer = new Thread() {
                @Override
                public void run() {
                    for (int i = 1; i < 10000; i++) {
                        System.out.println("生产元素: " + i);
                        try {
                            queue.put(i);
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            };
            producer.start();
            consumer.join();
            producer.join();
        }
    }

    Java中阻塞队列的示例分析

    运行结果如上。
    注意:

    • 1.wait和notify的正确使用

    • 2.put和take都会产生阻塞情况,但阻塞条件是对立的,wait不会同时触发(put唤醒take阻塞,take唤醒put阻塞)

    相关文章

    java速学教程(入门到精通)
    java速学教程(入门到精通)

    java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

    下载

    相关标签:

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

    热门AI工具

    更多
    DeepSeek
    DeepSeek

    幻方量化公司旗下的开源大模型平台

    豆包大模型
    豆包大模型

    字节跳动自主研发的一系列大型语言模型

    WorkBuddy
    WorkBuddy

    腾讯云推出的AI原生桌面智能体工作台

    腾讯元宝
    腾讯元宝

    腾讯混元平台推出的AI助手

    文心一言
    文心一言

    文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

    讯飞写作
    讯飞写作

    基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

    即梦AI
    即梦AI

    一站式AI创作平台,免费AI图片和视频生成。

    ChatGPT
    ChatGPT

    最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

    相关专题

    更多
    TypeScript类型系统进阶与大型前端项目实践
    TypeScript类型系统进阶与大型前端项目实践

    本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

    26

    2026.03.13

    Python异步编程与Asyncio高并发应用实践
    Python异步编程与Asyncio高并发应用实践

    本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

    46

    2026.03.12

    C# ASP.NET Core微服务架构与API网关实践
    C# ASP.NET Core微服务架构与API网关实践

    本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

    178

    2026.03.11

    Go高并发任务调度与Goroutine池化实践
    Go高并发任务调度与Goroutine池化实践

    本专题围绕 Go 语言在高并发任务处理场景中的实践展开,系统讲解 Goroutine 调度模型、Channel 通信机制以及并发控制策略。内容包括任务队列设计、Goroutine 池化管理、资源限制控制以及并发任务的性能优化方法。通过实际案例演示,帮助开发者构建稳定高效的 Go 并发任务处理系统,提高系统在高负载环境下的处理能力与稳定性。

    51

    2026.03.10

    Kotlin Android模块化架构与组件化开发实践
    Kotlin Android模块化架构与组件化开发实践

    本专题围绕 Kotlin 在 Android 应用开发中的架构实践展开,重点讲解模块化设计与组件化开发的实现思路。内容包括项目模块拆分策略、公共组件封装、依赖管理优化、路由通信机制以及大型项目的工程化管理方法。通过真实项目案例分析,帮助开发者构建结构清晰、易扩展且维护成本低的 Android 应用架构体系,提升团队协作效率与项目迭代速度。

    92

    2026.03.09

    JavaScript浏览器渲染机制与前端性能优化实践
    JavaScript浏览器渲染机制与前端性能优化实践

    本专题围绕 JavaScript 在浏览器中的执行与渲染机制展开,系统讲解 DOM 构建、CSSOM 解析、重排与重绘原理,以及关键渲染路径优化方法。内容涵盖事件循环机制、异步任务调度、资源加载优化、代码拆分与懒加载等性能优化策略。通过真实前端项目案例,帮助开发者理解浏览器底层工作原理,并掌握提升网页加载速度与交互体验的实用技巧。

    102

    2026.03.06

    Rust内存安全机制与所有权模型深度实践
    Rust内存安全机制与所有权模型深度实践

    本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

    227

    2026.03.05

    PHP高性能API设计与Laravel服务架构实践
    PHP高性能API设计与Laravel服务架构实践

    本专题围绕 PHP 在现代 Web 后端开发中的高性能实践展开,重点讲解基于 Laravel 框架构建可扩展 API 服务的核心方法。内容涵盖路由与中间件机制、服务容器与依赖注入、接口版本管理、缓存策略设计以及队列异步处理方案。同时结合高并发场景,深入分析性能瓶颈定位与优化思路,帮助开发者构建稳定、高效、易维护的 PHP 后端服务体系。

    532

    2026.03.04

    AI安装教程大全
    AI安装教程大全

    2026最全AI工具安装教程专题:包含各版本AI绘图、AI视频、智能办公软件的本地化部署手册。全篇零基础友好,附带最新模型下载地址、一键安装脚本及常见报错修复方案。每日更新,收藏这一篇就够了,让AI安装不再报错!

    171

    2026.03.04

    热门下载

    更多
    网站特效
    /
    网站源码
    /
    网站素材
    /
    前端模板

    精品课程

    更多
    相关推荐
    /
    热门推荐
    /
    最新课程
    Kotlin 教程
    Kotlin 教程

    共23课时 | 4.4万人学习

    C# 教程
    C# 教程

    共94课时 | 11.3万人学习

    Java 教程
    Java 教程

    共578课时 | 81.6万人学习

    关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
    php中文网:公益在线php培训,帮助PHP学习者快速成长!
    关注服务号 技术交流群
    PHP中文网订阅号
    每天精选资源文章推送

    Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号