【Java并发编程的艺术】Java并发容器和框架:Java中的阻塞队列

1.什么是阻塞队列

阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是 从队列里取元素的线程。阻塞队列就是生产者用来存放元素、消费者用来获取元素的容器。

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作支持阻塞的插入和移除方法。
1)支持阻塞的插入方法:意思是当队列满时,队列会阻塞插入元素的线程,直到队列不 满。
2)支持阻塞的移除方法:意思是在队列为空时,获取元素的线程会等待队列变为非空。

在阻塞队列不可用时,这两个附加操作提供了4种处理方式
【Java并发编程的艺术】Java并发容器和框架:Java中的阻塞队列

2.Java里的阻塞队列

JDK7提供了7个阻塞队列

2.1 ArrayBlockingQueue

由数组结构组成的有界阻塞队列。
此队列按照FIFO的原则对元素进行排序。

2.2 LinkedBlockingQueue

用链表结构组成的无界阻塞队列。
此队列按照FIFO的原则对元素进行排序。
此队列默认和最大长度为Integer.MAX_VALUE。

2.3 PriorityBlockingQueue

支持优先级排序的无界阻塞队列。默认情况下采取自然顺序升序排列。
不能保证同优先级元素的顺序

2.4 DelayQueue

使用优先级队列实现的无界在阻塞队列。支持延时获取元素。队列中的元素必须实现Delayed接口,再创建元素时可以指定多久才能从队列中获取当前元素。只有在延时期满时才能从队列中提取元素。

2.5 SynchronousQueue

不存储元素的阻塞队列。每一个put操作必须等待一个take操作,否则不能继续添加元素。
它的吞吐量高于ArrayBlockingQueue和LinkedBlockingQueue。

它支持公平访问队列。默认情况下线程采用非公平性策略访问队列。

2.6 LinkedTransferQueue

由链表结构组成的无界阻塞TransferQueue队列。
【Java并发编程的艺术】Java并发容器和框架:Java中的阻塞队列

2.7 LinkedBlockingDeque

由链表结构组成的双向阻塞队列。

在初始化LinkedBlockingDeque时可以设置容量防止其过度膨胀。另外,双向阻塞队列可以运用在“工作窃取”模式中。

3.阻塞队列的实现原理

使用通知模式实现
ArrayBlockingQueue使用了Condition来实现。

当往队列里插入一个元素时,如果队列不可用,那么阻塞生产者主要通过LockSupport.park(this)来实现。

park这个方法会阻塞当前线程,只有以下4种情况中的一种发生时,该方法才会返回。
1.与park对应的unpark执行或已经执行时。“已经执行”是指unpark先执行,然后再执行park的情况。
2.线程被中断时。
3.等待完time参数指定的毫秒数时。
4.异常现象发生时,这个异常现象没有任何原因。

当线程被阻塞队列阻塞时,线程会进入WAITING(parking)状态。