BlockingQueue是一个高性能的容器,它被用来线程之间共享数据,它是典型的生产者和消费者的实现。它支持两个附加的操作:读数据时等待队列变成非空;写数据时等待队列变成可写。JDK7提供了阻塞队列,它们分别是:
ArrayBlockingQueue 由数组组成的有界阻塞队列,必须指定队列的大小,遵循FIFO原则
LinkedBlockingQueue 由链表结构组成的有界阻塞队列,可改变大小的阻塞队列,遵循FIFO原则
PriorityBlockingQueue 支持优先级排序的无界阻塞阻塞队列,不是FIFO,而是有优先级的
DelayQueue 一个使用优先级队列实现的无界阻塞队列
SynchronousQueue:一个不存储元素的阻塞队列。每一插入必须等待另一个线程移除。
+LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
+LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
它定义了一种方法:
add(o)
,向队列插入一个元素,如果该操作无法立即执行,则抛出异常offer(o)
,向队列插入一个元素,如果该操作无法立即执行,返回一个特定的值,ture/falseput(o)
, 向队列插入一个元素,如果该操作无法立即执行,线程阻塞直到执行完毕后返回remove(o)
,删除队列一个元素,如果该操作无法立即执行,则抛出一个异常poll(o)
, 删除队列一个元素,如果该操作无法立即执行,则返回一个特性的值,true/falsetake(o)
, 删除队列一个元素,如果该操作无法立即执行,线程阻塞直到执行完毕后返回
注意,由于是队列操作,所以移除操作在非队首时,效率不高,建议不要这么做。
代码示例
下面使用ArrayBlockingQueue
演示简单的生产者和消费者模型:
ArrayBlockingQueue原理分析
阻塞队列的原理很简单,就是使用了ReentrantLock+Condition来实现线程的同步互斥,每次只有一个线程能够操作目标数组/链表;其他线程则阻塞等待Conditionde singal,下面是其关键的三个函数:
构造函数
|
|
put函数
|
|
enqueue函数
|
|
take函数
|
|
dequeue函数
|
|
由上可知,基于数组的阻塞队列的实现其实很简单,主要利用了可重入锁保证互斥的操作目标数组,当数组full的时候阻塞写线程await,并等待读进程的唤醒signal;同样的,当数组为空时,阻塞读线程,并等待写线程的唤醒。