【Java并发编程的艺术】Java并发容器和框架:Java中的阻塞队列
1.什么是阻塞队列
阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是 从队列里取元素的线程。阻塞队列就是生产者用来存放元素、消费者用来获取元素的容器。
阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作支持阻塞的插入和移除方法。
1)支持阻塞的插入方法:意思是当队列满时,队列会阻塞插入元素的线程,直到队列不 满。
2)支持阻塞的移除方法:意思是在队列为空时,获取元素的线程会等待队列变为非空。
在阻塞队列不可用时,这两个附加操作提供了4种处理方式
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队列。
2.7 LinkedBlockingDeque
由链表结构组成的双向阻塞队列。
在初始化LinkedBlockingDeque时可以设置容量防止其过度膨胀。另外,双向阻塞队列可以运用在“工作窃取”模式中。
3.阻塞队列的实现原理
使用通知模式实现。
ArrayBlockingQueue使用了Condition来实现。
当往队列里插入一个元素时,如果队列不可用,那么阻塞生产者主要通过LockSupport.park(this)来实现。
park这个方法会阻塞当前线程,只有以下4种情况中的一种发生时,该方法才会返回。
1.与park对应的unpark执行或已经执行时。“已经执行”是指unpark先执行,然后再执行park的情况。
2.线程被中断时。
3.等待完time参数指定的毫秒数时。
4.异常现象发生时,这个异常现象没有任何原因。
当线程被阻塞队列阻塞时,线程会进入WAITING(parking)状态。