阻塞队列BlockingQueue
- Queue、Deque、BlockingQueue的区别
- Queue(队列)
- 用于保存一组元素,在存取元素的时候必须
遵循先进先出
原则。
- 队列是一种特殊的线性表,只允许在表的前端(front)进行删除操作,在表的后端(rear)进行插入插座。
- 进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
- 队列中最先插入的元素将会被最先删除。
- 队列称为“先进先出”的线性表。
- Deque(双端队列)
- 两端都可以进出的队列。
- 当约束从队列的一端进出队时,遵循
先进后出
原则,即栈结构。
- 双端队列主要是用于栈操作,使用栈结构让操作有可追溯性。
- BlockingQueue(阻塞队列)
- 支持两个附加操作的队列,附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空;当队列满时,存储元素的线程会等待队列可用。
- 阻塞队列常用于生产者和消费者的场景,生产者是往队列中添加元素的线程,消费者是从队列里拿取元素的线程。阻塞队列是生产者存放元素的容器,消费者也只能从容器中拿取元素。
数组阻塞队列ArrayBlockingQueue
- ArrayBlockingQueue是一个
由数组支持的有界的阻塞队列
。队列按FIFO(先进先出)原则
对元素排序。
- 默认情况下,不保证访问者公平的访问队列。但可以通过代码创建公平的阻塞队列。
ArrayBlockingQueue fairQueue = new ArrayBlockingQueue(1000, true);
- 队列的头部是在队列中存在时间最长的元素,队列的队尾是在队列中存在时间最短的元素。
- 数组阻塞队列的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建就不能增加容量。
- 试图向已满队列汇总放入元素会导致操作受阻,试图从空队列中提取元素也将导致类似阻塞。
- 数组阻塞队列支持对等待的生产者线程和消费者线程进行排序的可选公平策略。通过将公平性(fairness)设置为true构造的队列允许按照FIFO顺序访问线程。
公平性通常会降低吞吐量,但也减少了可变性和避免“不平衡性”
。
链表阻塞队列LinkedBlockingQueue
- LinkedBlockingQueue是基于链表的阻塞队列,同ArrayListBlockingQueue类似,其内部维持着一个数据缓冲队列(该队列由一个链表构成)。队列按
FIFO(先进先出)原则
对元素排序。
- 生产者往队列中放入一个数据时,队列会从生产者手中获取数据,并缓存在队列内部,而生产者立即返回。只有当队列缓冲区达到最大值缓存容量时(LinkedBlockingQueue可以通过构造函数指定该值),才会阻塞生产者队列,直至消费者从队列汇总消费掉一份数据,生产者线程会被唤醒。
- LinkedBlockingQueue能够高效地处理并发数据,是因为
其对于生产者端和消费者端分别采用了独立的锁来控制数据同步
,在高并发的情况下生产者和消费者可以并行地操作队列中的数据
,以此提高整个队列的并发性能。
- LinkedBlockingQueue会默认一个类似无限大小的容量(Integer.MAX_VALUE)。
链表双向阻塞队列LinkedBlockingDeque
- LinkedBlockingDeque是一个由链表结构组成的
双向阻塞队列
。
- LinkedBlockingDeque新增了addFirst、addLast、offerFirst、等方法,以First结尾的方法,表示插入、获取双端队列的第一个元素,以Last结尾的方法,表示插入、获取双端队列的最后一个元素。
- 在初始化LinkedBlockingDeque时,可以
设置容量防止其过度膨胀
。双向阻塞队列可以运用在“工作窃取”模式(算法)中。
优先级阻塞队列PriorityBlockingQueue
- PriorityBlockingQueue是一个
支持优先级排序的无界阻塞队列
(优先级的判断通过构造函数传入的Compator
对象觉得决定),PriorityBlockingQueue并不会阻塞数据生产者,只会在没有可消费的数据时,阻塞数据的消费者。
- 生产者生产数据的速度绝对不能快于消费者消费数据的速度,否则时间一长,会最终耗尽所有的可用堆内存空间。
- 实现PriorityBlockingQueue时,内部控制线程同步的锁采用
公平锁
。
延时队列DelayQueue