Java中ArrayBlockingQueue和LinkedBlockingQueue

yizhihongxing

简介:

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日

相关文章

  • SpringBoot统计、监控SQL运行情况的方法详解

    关于SpringBoot统计、监控SQL运行情况的方法,可以采用以下两种方式实现: 1. 使用Druid Spring Boot Starter Druid Spring Boot Starter是阿里巴巴为了简化Druid在Spring Boot中的配置而推出的开箱即用的库。它基于Druid DataSource和Spring Boot自动配置机制,并提供…

    Java 2023年5月20日
    00
  • 两种java文件上传实例讲解

    下面是详细讲解“两种java文件上传实例讲解”的攻略: 一、基于Spring MVC框架的文件上传实例 1. 在Maven项目配置中添加以下依赖: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</…

    Java 2023年5月19日
    00
  • java中Hibernate的状态总结

    Java中Hibernate的状态总结 Hibernate是Java中广泛使用的ORM(对象关系映射)框架之一,其核心原则是使用Java对象来映射数据库表格。在使用Hibernate时,需要注意对象实例所处的状态,本文将对Hibernate中的状态进行总结。 Hibernate对象状态 下面是Hibernate对象可能出现的几种状态: Transient状态…

    Java 2023年5月19日
    00
  • Java实现DES加解密算法解析

    Java实现DES加解密算法解析 DES算法简介 DES(Data Encryption Standard)是一种对称加密算法,是现今使用最普遍的加密算法之一。它使用64位密钥对64位的数据进行加密和解密,加密和解密使用相同的密钥,是一种对称算法。 DES算法分组加密,每次加密的明文长度为64bit,密钥长度为64bit,加密过程中,将明文分成64bit一组…

    Java 2023年5月26日
    00
  • hibernate 常用方法介绍

    Hibernate 常用方法介绍 Hibernate 是一个流行的 ORM 工具,它可以大大简化数据库操作过程。本文将介绍一些 Hibernate 的常用方法。 配置 Hibernate 在使用 Hibernate 之前,我们需要进行配置。以下是配置 Hibernate 的基本步骤: 添加项目依赖,包括 Hibernate 核心库、连接池和数据库驱动等。 创…

    Java 2023年5月19日
    00
  • java密钥交换算法DH定义与应用实例分析

    Java密钥交换算法DH定义与应用实例分析 什么是DH算法? DH全称是Diffie-Hellman密钥交换算法,是一种安全的密钥交换协议。该算法的基本思路是:两个通信方都选择一组数字作为私有密钥,然后通过数学运算得出一个公用密钥。由于计算过程需要在一定范围内生成大的素数和进行模幂运算等数学问题,因此DH算法是一种非常安全、不易被破解的密钥交换方式。 DH算…

    Java 2023年5月26日
    00
  • java.net.ConnectException: Connection refused问题解决办法

    当Java应用程序尝试连接到另一个应用程序或服务器但无法建立连接时,你可能会遇到 java.net.ConnectException: Connection refused 异常。这种情况通常表示目标主机拒绝连接或者连接超时。下面是解决此问题的完整攻略: 1. 检查目标服务器/应用程序是否正在运行 首先,你需要确保你所连接的应用程序或服务器正在运行。 如果目…

    Java 2023年5月27日
    00
  • Java数字签名算法DSA实例详解

    Java数字签名算法DSA实例详解 什么是数字签名算法? 数字签名算法是指利用公开密钥加密算法,对某些信息进行加密以验证信息的完整性、来源和真实性的技术。数字签名通常使用私钥进行签名和公钥进行验证。 DSA数字签名算法介绍 DSA是数字签名算法(Digtial Signature Algorithm)的缩写,是美国国家安全局(NSA)和国家标准局(NIST)…

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