什么是阻塞队列
阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作是: 在队列为空时, 获取元素的线程会等待队列变为非空。当队列满时, 存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景, 生产者是往队列里添加元素的线程, 消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器, 而消费者也只从容器里拿元素。
- 当队列是空的, 从队列中获取元素的操作将会被阻塞
- 当队列是满的, 从队列中添加元素的操作将会被阻塞
- 试图从空的队列中获取元素的线程将会被阻塞, 直到其他线程往空的队列插入新的元素
- 试图向已满的队列中添加新元素的线程将会被阻塞, 直到其他线程从队列中移除一个或多个元素或者完全清空, 使队列变得空闲起来并后续新增
阻塞队列种类
-
ArrayBlockingQueue
- 基于数组构成的有界阻塞队列
- 在生产者插入数据和消费者获取数据时用的是同一把锁, 无法并行
-
LinkedBlockingQueue
- 基于链表构成的有界(默认值为
Integer.MAX_VALUE
)阻塞队列 - 插入数据和获取数据分别采用了独立的锁, 有较好的并发性能
- 基于链表构成的有界(默认值为
-
DelayQueue
- 基于优先级队列实现的延迟无界阻塞队列
- DelayQueue 中的元素只有当其指定的延迟时间到了, 才能够从队列中获取到该元素。
- DelayQueue 是一个没有大小限制的队列, 因此往队列中插入数据的操作永远不会被阻塞, 只有获取数据的操作才会被阻塞
-
PriorityBlockingQueue
- 基于优先级队列实现的无界阻塞队列
- 支持优先级排序
- 不会阻塞生产者, 当队列中没有数据时, 会阻塞消费者
-
SynchronousQueue
- 一种无缓冲的等待队列
- 相对于有缓冲的BlockingQueue来说, 少了一个中间环节(缓冲区)
- 不存储元素, 是一个单个元素的队列
SynchronousQueue公平模式与非公平模式的区别
- 公平模式: SynchronousQueue 会采用公平锁, 并配合一个 FIFO 队列来阻塞多余的生产者和消费者, 从而体系整体的公平策略
- 非公平模式(默认):SynchronousQueue 采用非公平锁, 同时配合一个 LIFO 队列来管理多余的生产者和消费者, 再高并发的情况下容易出现线程饥饿
-
LinkedTransferQueue
- 基于链表结构实现的无界TransferQueue队列
- 预占模式: 意思就是消费者线程取元素时, 如果队列不为空, 则直接取走数据, 若队列为空, 生成一个节点(元素为 null)入队, 消费者线程被等待在这个节点上, 生产者线程入队时发现有一个元素为 null 的节点, 生产者线程就不入队了, 直接就将元素填充到该节点, 并唤醒该节点等待的线程, 被唤醒的消费者线程取走元素, 从调用的方法返回
-
LinkedBlockingDeque
- 基于链表实现的双向有界阻塞队列
- 可以从队列的两端插入和移除元素, 双向队列因为多了一个操作队列的入口, 在多线程同时入队时, 也就减少了一半的竞争
- 插入元素时: 如果当前队列已满将会进入阻塞状态, 一直等到队列有空的位置时再该元素插入, 该操作可以通过设置超时参数, 超时后返回 false 表示操作失败, 也可以不设置超时参数一直阻塞, 中断后抛出 InterruptedException异常
- 读取元素时: 如果当前队列为空会阻塞住直到队列不为空然后返回元素, 同样可以通过设置超时参数
核心方法
方法类型 | 抛出异常 | 特殊值 | 阻塞 | 超时 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
检查 | element() | peek() | NA | NA |
各种方法类型的具体效果
方法类型 | 效果 |
---|---|
抛出异常 | 当阻塞队列满时, 再往队列里add插入元素会抛出IllegalStateException:Queue full 当阻塞队列空时, 再对队列remove移除元素会抛出NoSuchElementException |
特殊值 | 插入方法, 成功返回true, 失败返回false 移出方法, 成功返回取出的元素, 失败返回null |
阻塞 | 当阻塞队列满时, 生产者线程继续往队列里put元素, 队列就会一直阻塞生产者知道put数据成功或中断退出 当阻塞队列空时, 消费者线程试图从队列里take元素, 队列就会一直阻塞消费者线程知道队列里有数据 |
超时 | 当阻塞队列满时, 队列会阻塞生产者线程, 超过等待时限后生产者线程会退出 当阻塞队列空时, 队列会阻塞消费者线程, 超过等待时限后消费者线程会退出 |
我的个人主页: www.ayu.link
本文连接: ┏ (゜ω゜)=☞