Java 中LinkedBlockingQueue和ArrayBlockingQueue

2024-02-21 14:28

本文主要是介绍Java 中LinkedBlockingQueue和ArrayBlockingQueue,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

什么是LinkedBlockingQueue和ArrayBlockingQueue

LinkedBlockingQueue和ArrayBlockingQueue都是Java中常用的阻塞队列(BlockingQueue)实现类。它们的主要区别和特点如下:

  1. 数据结构:LinkedBlockingQueue基于链表实现,而ArrayBlockingQueue基于数组实现。
  2. 容量限制:LinkedBlockingQueue在创建时可以指定一个可选的容量参数,如果不指定容量,则默认容量为Integer.MAX_VALUE,因此它可以持续地添加任务,不会抛出队列满的异常。而ArrayBlockingQueue在创建时需要指定容量,且一旦设置就无法更改。当队列满时,后续任务将会被阻塞,直到队列中有空闲位置。
  3. 队列操作的性能:由于LinkedBlockingQueue采用链表实现,对于元素的插入和删除操作性能比较高。然而,对于随机访问元素的操作,由于需要遍历链表,性能比较低。而ArrayBlockingQueue采用数组实现,对于插入和删除操作性能也比较高。此外,由于数组支持随机访问,对于随机访问元素的操作性能也比较高。
  4. 阻塞操作的支持:LinkedBlockingQueue和ArrayBlockingQueue都支持阻塞操作。但是,它们的具体实现方式有所不同。LinkedBlockingQueue在插入和删除元素时,如果队列已满或为空,则会阻塞线程,直到队列有足够的空间或元素。而ArrayBlockingQueue在插入和删除元素时,如果队列已满或为空,则会立即阻塞线程,直到队列有足够的空间或元素。
  5. 内存占用:由于LinkedBlockingQueue采用链表实现,每个元素需要一个节点对象来保存。因此,如果队列中的元素比较多,LinkedBlockingQueue会占用更多的内存。而ArrayBlockingQueue采用数组实现,每个元素只需要一个数组元素来保存,因此内存占用相对较少。

总的来说,LinkedBlockingQueue适用于任务量不断增加的情况,可以无限制地添加任务,适合使用在不限制任务数量的场景。而ArrayBlockingQueue则适用于有固定容量限制的场景,可以确保队列的大小不会超过预设的容量。在选择使用哪种阻塞队列时,应根据具体的应用场景和需求进行权衡。

使用示例

LinkedBlockingQueueArrayBlockingQueue在Java编程中常常用于实现生产者-消费者模式,以及多线程之间的协作。以下是两种队列的使用示例:

ArrayBlockingQueue示例

import java.util.concurrent.ArrayBlockingQueue;public class ArrayBlockingQueueExample {public static void main(String[] args) throws InterruptedException {// 创建一个有界队列,容量为10ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);// 启动生产者线程Thread producer = new Thread(() -> {for (int i = 0; i < 20; i++) {try {System.out.println("生产者生产了: " + i);queue.put(i); // 将元素放入队列,如果队列满则阻塞Thread.sleep(1000); // 模拟生产耗时} catch (InterruptedException e) {e.printStackTrace();}}});// 启动消费者线程Thread consumer = new Thread(() -> {while (true) {try {Integer item = queue.take(); // 从队列中取出元素,如果队列空则阻塞System.out.println("消费者消费了: " + item);Thread.sleep(1500); // 模拟消费耗时} catch (InterruptedException e) {e.printStackTrace();}}});// 启动生产者和消费者线程producer.start();consumer.start();// 等待生产者线程完成producer.join();// 停止消费者线程(实际场景中可能需要根据实际情况来决定何时停止消费者线程)consumer.interrupt();}
}

LinkedBlockingQueue示例

import java.util.concurrent.LinkedBlockingQueue;public class LinkedBlockingQueueExample {public static void main(String[] args) throws InterruptedException {// 创建一个无界队列,或者可以指定一个容量LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue<>();// 启动生产者线程Thread producer = new Thread(() -> {for (int i = 0; i < 20; i++) {try {System.out.println("生产者生产了: " + i);queue.put(i); // 将元素放入队列,如果队列满则阻塞Thread.sleep(1000); // 模拟生产耗时} catch (InterruptedException e) {e.printStackTrace();}}});// 启动消费者线程Thread consumer = new Thread(() -> {while (true) {try {Integer item = queue.take(); // 从队列中取出元素,如果队列空则阻塞System.out.println("消费者消费了: " + item);Thread.sleep(1500); // 模拟消费耗时} catch (InterruptedException e) {e.printStackTrace();}}});// 启动生产者和消费者线程producer.start();consumer.start();// 等待生产者线程完成producer.join();// 停止消费者线程(实际场景中可能需要根据实际情况来决定何时停止消费者线程)consumer.interrupt();}
}

在以上两个示例中,生产者和消费者线程通过puttake方法进行通信。当队列满时,生产者线程会阻塞,直到队列中有空位;当队列空时,消费者线程会阻塞,直到队列中有元素可取。这样,生产者和消费者就可以在并发环境下安全地协作。

请注意,在实际应用中,我们通常会使用更优雅的方式来停止消费者线程,而不是简单地调用interrupt()方法。例如,我们可以使用一个特殊的结束信号(如null或一个特殊的值)来表示队列中不再有新的元素,消费者线程在检测到这个信号后可以安全地结束。

这篇关于Java 中LinkedBlockingQueue和ArrayBlockingQueue的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/732087

相关文章

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2

Java实现在Word文档中添加文本水印和图片水印的操作指南

《Java实现在Word文档中添加文本水印和图片水印的操作指南》在当今数字时代,文档的自动化处理与安全防护变得尤为重要,无论是为了保护版权、推广品牌,还是为了在文档中加入特定的标识,为Word文档添加... 目录引言Spire.Doc for Java:高效Word文档处理的利器代码实战:使用Java为Wo

SpringBoot日志级别与日志分组详解

《SpringBoot日志级别与日志分组详解》文章介绍了日志级别(ALL至OFF)及其作用,说明SpringBoot默认日志级别为INFO,可通过application.properties调整全局或... 目录日志级别1、级别内容2、调整日志级别调整默认日志级别调整指定类的日志级别项目开发过程中,利用日志

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有