# 前言

阻塞队列是当队列空或满的情况下,能够阻塞消费者或生产者,然后在队列有数据或有空位置的时候,能够唤醒被阻塞的线程。

# 常见阻塞队列

Java 中有 7 种常见的阻塞队列:

  1. ArrayBlockingQueue
  2. LinkedBlockingQueue
  3. PriorityBlockingQueue
  4. DelayQueue
  5. SynchronousQueue
  6. LinkedTransferQueue
  7. LinkedBlockingDeque

他们的类图结构如图:

常见阻塞队列类图

可以看出,他们都继承了一个队列的抽象类 AbstractQueue,实现了阻塞队列接口 BlockingQueue,AbstractQueue 和 BlockingQueue 都实现或继承了 Queue 接口。

# 主要区别

  • ArrayBlockingQueue 是基于数组实现的有界阻塞队列,先进先出,可指定是否使用公平锁,使用循环双指针来指定头结点和尾结点位置。多线程使用一把锁来同步所有操作,使用两个 condition 来等待队列非空或非满。

  • LinkedBlockingQueue 是基于链表实现的有界阻塞队列,两个节点分别指向头结点和尾结点。通过双锁算法用两个锁来分别同步移除和插入操作,两个 condition 来等待队列非空或非满,直接使用默认的非公平锁。

  • PriorityBlockingQueue 是具有优先级的无界阻塞队列,底层使用数组实现,队列默认大小是 11,最大值是整型 - 8,可以自定义优先级比较器。使用一个锁来控制所有操作的同步,一个 condition 来等待队列非空,扩容操作通过 CAS 锁进行同步。

  • DelayQueue 是具有延时的无界阻塞队列,底层使用优先队列实现,元素必须继承 Delayed 接口,实现 getDelay 和 compareTo 方法。使用一个锁来同步所有操作,用 Leader/Follower 模式来移除元素,一个 condition 来等待队列非空或头结点移除。

  • SynchronousQueue 是没有容量的阻塞队列,通常用来在生产者和消费者之间传输,元素状态分为 消费、生产、匹配状态。每一个 put 操作必须等待一个 take 操作,否则不能继续 put,反之亦然。

  • LinkedTransferQueue 是由链表组成的无界阻塞队列,实现了 TransferQueue 接口,相较于其他阻塞队列多了 tryTransfer 和 transfer 方法,在生产者插入数据时,如果有消费者来消费数据,直接传递给消费者。

  • LinkedBlockingDeque 是基于链表的有界双向阻塞队列,可以运用在窃取算法中。

# 主要方法

主要方法有插入、移除和检查,阻塞策略有抛异常、返回特殊值(null 或 false,视情况而定)、阻塞和超时(先阻塞,超时后返回特殊值)。

方法类型抛出异常特殊值阻塞超时
插入add(e)offer(e)put(e)offer(e, timeout, unit)
移除remove()poll()take()poll(time, unit)
检查element()peek()----

抛出异常的方式实现继承自 AbstractQueue,特殊值、阻塞和超时的方法,都实现了 BlockingQueue。