深入浅出阻塞队列BlockingQueue及其典型实现ArrayBlockingQueue

本篇我们将一起对 AQS的另一类的应用场景的实现类——阻塞队列(实现生产者/消费者模型的经典方法) 做一次深入浅出的分析。

老套路,从UML类图开始

从上面的类图结构和源码的注释分析来看,我总结如下:

  • 第一,BlockingQueue是一个接口,它继承了Queue,Collection,Iterable几大接口的属性和方法。
  • 第二,BlockingQueue继承了Queue,并且进行了进一步的扩展,从而具备以下四种特性:
    • (1)有些方法可抛出异常
    • (2)有些方法可返回特殊值,如NULL或者false,取决于各个方法
    • (3)有些方法能够无限期的阻塞当前线程,直到操作成功
    • (4)有些方法的阻塞操作可以设定最大的时间限制
  • 第三,BlockingQueue不支持添加空元素,当你试图通过add,put,offer方法添加null,会报错;但是null可以被用来标注为特殊返回值,代表一些操作失败了,比如poll等操作
  • 第四,BlockingQueue可能在容量上有限制,即在给定的时间内,它都可能具有剩余容量,超过该容量就不能继续添加了,除非方法是阻塞特性的(为啥?后面会说)。当你没有设置容量大小时,一般默认大小是Integer.MAX_VALUE。
  • 第五,BlockingQueue的实现是线程安全的。所有的有关队列操作的方法,它的实现其内部大多都是使用内部锁或者并发控制以原子方式实现的(如利用ReentrantLock等工具),但是除了一些批量操作则不一定是具备原子操作属性的,毕竟是批量嘛。
  • 第六,BlockingQueue从本质上来说,是不支持类似close或者shutdown这样子的操作的,以表示不能再进行任何操作。当然,如果业务实在需要,你也可以自己自定义实现。
  • 第七,BlockingQueue和其他的并发容器或者工具类一样,一个线程的入队操作是要发生在另一个线程的访问或者删除操作之前,是符合happen-before原则滴。
  • 第八,也是压轴,BlockingQueue的实现主要用于生产者/消费者队列,且还支持集合Collection的特性(所以队列支持类似remove之类的操作,但是这种操作往往性能不会很高,我们也不经常使用)。此外,BlockingQueue可以在生产者/消费者场景中支持多个生产者和多个消费者。

BlockingQueue方法介绍

从上面总结的第一和第二点我们知道,BlockingQueue的接口方法包含四种类型的: 会抛异常的、返回特殊值的、会阻塞的和阻塞有超时的 ;但是按照操作结果大体可分为三种(官方区分的): 插入型的、删除型的、读取型的 。如下面的表格总结(其实也是源码的注释内容):

下面我们就此表格说明下( 我又多分了一个种类->读取删除型 ,这样更清晰些):

  • 常规操作
    • 插入型:
      • boolean add(e),向队列插入元素,成功返回true,如果队列容量不够了,则抛出IllegalStateException
      • boolean offer(e),向队列插入元素,成功true,失败false,队列容量不够,不会抛出异常
    • 删除型:
      • boolean remove(o),从队列删除指定的元素o,如果队列里存在多个e,且o.equals(e),则所有e都删除,返回值boolean
    • 读取型:
      • E element(),读取队头元素数据,但是不删除元素,如果队列为空,则会抛出异常
      • E peek(),和element一样,但是队列为空,它就返回null
    • 读取删除型:
      • E poll(),读取并删除队头数据,如果队列为空,则返回空,否则返回头节点元素,即此方法既是取又是删
  • BlockingQueue扩展操作 (阻塞超时)(生产者/消费者实现的核心)
    • 插入型:
      • v oid put(e),阻塞插入,将元素插入队列,如果队列满了,则会阻塞线程等待,直到队列有空于的节点可供插入
      • boolean offer(e,timeout,unit),和上面put一样,但是等待有时间限制,到了超时的时间,就会退出
    • 读取删除型:
      • E take(),阻塞读取删除队头元素数据,如果队列为空,则会阻塞线程等待,直到队列有数据添加了,才会继续执行
      • E poll(timeout,unit),和上面take一样,但是阻塞等待
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BlockingQueueJava中的一个并发集合,它提供了线程安全的队列操作方式,其中包括添加、删除、检索操作等。它的主要特点是在队列为空时获取元素将会阻塞,而在队列满时添加元素也会阻塞。 ArrayBlockingQueue和LinkedBlockingQueue都是BlockingQueue的具体实现。 1. ArrayBlockingQueueArrayBlockingQueue是一个有界阻塞队列,它的内部是通过一个数组来实现的。当阻塞队列已满时,再往队列中添加元素的操作将会被阻塞;当队列为空时,取队列元素的操作将会被阻塞。 ArrayBlockingQueue的主要特点如下: - 内部实现是数组 - 有界队列,容量是固定的 - 在队列满时添加元素会被阻塞 - 在队列空时获取元素会被阻塞 2. LinkedBlockingQueue: LinkedBlockingQueue是一个无界阻塞队列,它内部采用链表来实现。LinkedBlockingQueue容量可以无限扩大,但是应该尽量设置合适的容量,以避免过度膨胀而导致内存泄漏等问题。 LinkedBlockingQueue的主要特点如下: - 内部实现是链表 - 无界队列,容量可以无限扩大 - 在队列满时添加元素会被阻塞 - 在队列空时获取元素会被阻塞 综上所述,ArrayBlockingQueue和LinkedBlockingQueue的最大区别就在于:一个是有界队列,一个是无界队列。对于不同的业务场景,需要根据实际需求选择合适的实现方式。如果在队列扩容方面比较苛刻或者需要限制队列的大小,可以选择ArrayBlockingQueue;如果对队列长度没有明确限制,可以选择LinkedBlockingQueue

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值