Java中ArrayBlockingQueue和LinkedBlockingQueue

简介:

Java中的BlockingQueue是java.util.concurrent包中的一个接口,是JDK中的并发工具,提供了线程安全的队列,可以用来协调生产者与消费者线程的生产和消费的速度,并且解决了高并发下数据读写的安全问题。BlockingQueue具有阻塞的复杂行为,可以实现生产、消费线程集合的同步。

Java中有两个BlockingQueue的实现类ArrayBlockingQueue和LinkedBlockingQueue,两者都实现了BlockingQueue接口,但是在实现细节上有所不同,下面将对它们进行详细讲解。

一、ArrayBlockingQueue

ArrayBlockingQueue是一个有界阻塞队列,它的容量固定,在创建时必须指定容量大小,并且不可更改。它内部以数组进行实现,因此其读写速度较快。

1.1 初始化

ArrayBlockingQueue的初始化需要指定容量大小,如下所示:

BlockingQueue<String> queue = new ArrayBlockingQueue<>(capacity);

其中capacity表示队列的容量大小。

1.2 队列操作

ArrayBlockingQueue提供了一系列的队列操作方法,例如:

  • add(E e) 将指定元素插入此队列。
  • put(E e) 将指定元素插入此队列,如有必要阻塞线程等待可用。
  • take() 移除并返回此队列的头部,如果此队列为空,则阻塞线程等待可用。
  • poll() 检索并移除此队列的头,如果此队列为空,则返回 null。

示例:

BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);

queue.add("A");
queue.add("B");
queue.add("C");// 添加第三个元素,会抛出IllegalStateException异常

运行结果:

Exception in thread "main" java.lang.IllegalStateException: Queue full
    at java.util.AbstractQueue.add(AbstractQueue.java:98)
    at java.util.concurrent.ArrayBlockingQueue.add(ArrayBlockingQueue.java:312)

从上面的运行结果中可以看出,当添加元素达到队列容量时,再次添加元素会抛出IllegalStateException异常。

示例:

BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);

queue.put("A");
queue.put("B");
queue.put("C");// 阻塞线程,直到队列中有空闲位置

String element = queue.take();// 从队列中取出元素,如果队列为空则阻塞线程,直到有可用元素

1.3 等待超时操作

ArrayBlockingQueue还提供了等待超时操作的方法,例如:

  • offer(E e, long timeout, TimeUnit unit) 将指定元素插入此队列,并在指定的等待时间内等待空间变得可用。
  • poll(long timeout, TimeUnit unit) 检索并移除此队列的头,如果此队列为空,则在指定的等待时间内等待可用元素。

示例:

BlockingQueue<String> queue = new ArrayBlockingQueue<>(2);

queue.offer("A", 1000, TimeUnit.MILLISECONDS);
queue.offer("B", 1000, TimeUnit.MILLISECONDS);
queue.offer("C", 1000, TimeUnit.MILLISECONDS);// 阻塞线程,直到队列中有空闲位置,等待1秒

String element = queue.poll(1000, TimeUnit.MILLISECONDS);// 从队列中取出元素,如果队列为空则等待1秒,直到有可用元素

二、LinkedBlockingQueue

LinkedBlockingQueue是一个无界阻塞队列,它的容量没有限制,在创建时可以选择是否指定容量大小。它内部以链表进行实现,因此其读写速度较慢,但是其容量不受限制,可以用于解决任务生产速度与消费速度不一致的场景。

2.1 初始化

LinkedBlockingQueue的初始化可以选择是否指定容量大小,如下所示:

BlockingQueue<String> queue = new LinkedBlockingQueue<>();

或者指定容量大小,例如:

BlockingQueue<String> queue = new LinkedBlockingQueue<>(capacity);

其中capacity表示队列的容量大小,如果不指定则默认为Integer.MAX_VALUE。

2.2 队列操作

LinkedBlockingQueue也提供了一系列的队列操作方法,与ArrayBlockingQueue的方法类似,例如:

  • add(E e) 将指定元素插入此队列。
  • put(E e) 将指定元素插入此队列,如有必要阻塞线程等待可用。
  • take() 移除并返回此队列的头部,如果此队列为空,则阻塞线程等待可用。
  • poll() 检索并移除此队列的头,如果此队列为空,则返回 null。

示例:

BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);

queue.add("A");
queue.add("B");
queue.add("C");// 添加第三个元素,不会抛出异常

String element = queue.poll();// 从队列中取出元素,如果队列为空则返回null

示例:

BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);

queue.put("A");
queue.put("B");
queue.put("C");// 阻塞线程,直到队列中有空闲位置

String element = queue.take();// 从队列中取出元素,如果队列为空则阻塞线程,直到有可用元素

2.3 等待超时操作

LinkedBlockingQueue也提供了等待超时操作的方法,例如:

  • offer(E e, long timeout, TimeUnit unit) 将指定元素插入此队列,并在指定的等待时间内等待空间变得可用。
  • poll(long timeout, TimeUnit unit) 检索并移除此队列的头,如果此队列为空,则在指定的等待时间内等待可用元素。

示例:

BlockingQueue<String> queue = new LinkedBlockingQueue<>(2);

queue.offer("A", 1000, TimeUnit.MILLISECONDS);
queue.offer("B", 1000, TimeUnit.MILLISECONDS);
queue.offer("C", 1000, TimeUnit.MILLISECONDS);// 阻塞线程,直到队列中有空闲位置,等待1秒

String element = queue.poll(1000, TimeUnit.MILLISECONDS);// 从队列中取出元素,如果队列为空则等待1秒,直到有可用元素

总结:

ArrayBlockingQueue和LinkedBlockingQueue都是BlockingQueue的实现类,都可以用来实现生产者和消费者模型,但是它们在实现方式上有所不同。ArrayBlockingQueue是一个有界阻塞队列,内部以数组进行实现,读写速度较快;LinkedBlockingQueue是一个无界阻塞队列,内部以链表进行实现,读写速度较慢。

当生产者的速度大于消费者的速度时,ArrayBlockingQueue可以避免队列无限增长的问题;当生产者和消费者速度相差不大,或者需要无限制地添加元素时,可以选择使用LinkedBlockingQueue。

参考文章:https://www.jianshu.com/p/97cccbb9fc99

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中ArrayBlockingQueue和LinkedBlockingQueue - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • Java实现链栈的示例代码

    Java链栈是一种特殊的栈,底层是使用单向链表实现的,相比较数组实现栈的方式,链栈可以无需考虑容量的问题,能够动态地适应数据结构的需求。下面详细讲解Java实现链栈的示例代码的完整攻略。 1. 实现链栈的基本步骤 Java实现链栈的基本步骤如下: 定义链栈的节点类 定义链栈类,包含入栈、出栈、查看栈顶数据等方法 在链栈类中,定义一个栈顶节点对象,然后在入栈、…

    Java 2023年5月18日
    00
  • 图解Java经典算法冒泡排序的原理与实现

    下面详细讲解一下“图解Java经典算法冒泡排序的原理与实现”的完整攻略。 冒泡排序的原理 冒泡排序是一种基础的排序算法,它是通过比较相邻元素的大小来进行排序的。具体来说,它的原理是: 比较相邻的两个元素,如果前面的元素大于后面的元素,就交换它们的位置。 对每一对相邻元素做相同的操作,从开始的第一对直到结尾的最后一对。这样一轮下来,就能把最大元素排到最后。 对…

    Java 2023年5月19日
    00
  • Springboot通用mapper和mybatis-generator代码示例

    下面是关于“Springboot通用mapper和mybatis-generator代码示例”的完整攻略: 一、什么是Springboot通用mapper和mybatis-generator 1. Springboot通用mapper Springboot通用mapper是一款能够提高数据访问的工具,主要用于深度整合Mybatis和Spring Data J…

    Java 2023年5月20日
    00
  • SpringBoot DataSource数据源实现自动配置流程详解

    这里是关于SpringBoot DataSource数据源实现自动配置流程的详细攻略: 1. SpringBoot DataSource数据源的概述 SpringBoot 数据源(DataSource)是一个非常重要的组件,它是应用程序和后端数据库之间的桥梁。DataSource 有两个关键任务:一是管理数据库连接池,以便应用可以快速、高效地访问数据库;二是…

    Java 2023年6月2日
    00
  • IDEA创建SpringBoot的maven项目的方法步骤

    创建Spring Boot的Maven项目是一个常见的任务,使用IntelliJ IDEA可以轻松完成。在本文中,我们将详细讲解如何使用IntelliJ IDEA创建Spring Boot的Maven项目,包括如何选择Spring Boot版本、如何配置Maven、如何添加依赖项等。 步骤 以下是使用IntelliJ IDEA创建Spring Boot的Ma…

    Java 2023年5月15日
    00
  • SpringBoot自定义/error路径失效的解决

    下面是对于“SpringBoot自定义/error路径失效的解决”的完整攻略: 背景 在使用SpringBoot开发web应用的过程中,我们有时需要自定义error处理页面。按照惯例,我们可以将静态页面放在/resources/static/error路径下,然后在Controller层中自定义处理对应的erroCode,比如404、500等。这样,当用户访…

    Java 2023年5月26日
    00
  • 实例详解JSON取值(key是中文或者数字)方式

    好的!JSON是一种常用的数据格式,在前端开发中经常会用到。本篇攻略主要介绍如何在JSON中取值,并且针对key是中文或数字的情况进行详细讲解,下面开始具体介绍。 JSON简介 JSON是JavaScript对象表示法的缩写,是一种轻量级的数据交换格式,可读性高,易于编写和解析。JSON可以表示数字、字符串、布尔值、数组、对象和null,是前端开发中常用的数…

    Java 2023年5月26日
    00
  • Spring Boot 如何自定义返回错误码错误信息

    一、背景知识 在开发过程中,定义一套统一的错误码以及错误信息对于后续的使用和协作有很大的帮助,这笔帮助在项目人员的交流、定位问题、维护代码等方面会发挥至关重要的作用。 Spring Boot 是一个优秀的开源框架,同样也提供了很多途径来自定义错误码以及错误信息,因此本文打算讲解一下如何在 Spring Boot 中自定义返回错误码和错误消息的过程。 二、应用…

    Java 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部