您的位置 首页 java

java并发包系列(九)-阻塞队列BlockingQueue

什么是阻塞队列(BlockingQueue)?生产者/消费者模型应该都听过或者实际也用过,生产者负责产出任务,消费者负责消费任务,这就需要一个队列来存储这些任务,提供相应的方法获取和增加任务,写过简单生产者/消费者模型代码都知道,在队列为空时,消费者会等待队列变为非空;当队列满时,生产者会等待队列可用。 java 并发包中BlockingQueue按照功能和处理方式,可得到以下:(好像经常有面试问道)

抛出异常

当队列已满,再往队列中丢入任务,会抛出IllegalStateException(“Queue full”);当队列空了,从队列中取出任务或者检查是否存在任务,则会抛出NoSuchElementException;

返回特殊值

相对于抛出异常,插入元素失败不会抛出异常,而是返回 false ;移除和检查若失败则会返回null.

阻塞

当队列已经满,再往队列尝试添加任务,则会被队列阻塞,直到自己被消费者唤醒且队列不满,或者直接相应中断;同理当队列为空时,再尝试获取元素,则或被队列阻塞,直到被生产者线程唤醒且队列不为空。

超时退出

当阻塞队列满时,再往队列尝试添加任务,队列会阻塞生产者线程一段时间,如果超过一定的时间,生产者线程就会退出返回false;当队列为空,尝试移除元素,队列也是会阻塞线程一段时间,如果超时,线程会退出运行并返回null。

除了以上方法阻塞队列还提供了drainTo(c)、remainingCapacity()方法,

drainTo(Collection c)/ drainTo(Collection c,max)

该方法从队列中移除元素,并将他们添加到结合中,通过该方法可以提高数据获取效率,不需要多次的锁获取和释放。一次性就可以获取指定或者全部的数据。drainTo(c)表示移除所有可用元素,(其实现是通过调用drainTo(Collection c,max),max值为Integer.Max)

remainingCapacity()

返回在无阻塞的理想情况下此队列能接受的元素数量,解释一下就是通过加锁方式获取到当前队列所能够容纳元素数量;如果没有内部限制,则返回 Integer.MAX_VALUE,比如无界队列PriorityBlockingQueue,像ArrayBlockingQueue这类有界队列则会返回容纳数据的具体数量。

BlockingQueue主要家族成员以及相互关系如下:

以BlockingQueue为中心,分为上下两部分,下部分为单向阻塞队列,上半部分为双向的阻塞队列,实现目前JDK8只有一个LinkedBlockingDeque,相比单向队列,双向队列可以从队列头部和尾部增加或者删除元素,针对双向队列多出以下方法:

相对于单向队列,双向队列多了xxxFirst() xxxLast方法,双向队列 add() offer()最终实现都是调用xxxLast()。分别简单介绍java阻塞队列家族成员。

ArrayBlockingQueue

ArrayBlockingQueue是一个用数组实现的有界阻塞队列。内部维持着一个定长数据缓冲队列。内部还保存着两个整形变量,分别标识着队列的头部和尾部在数组中的位置。此队列按照先进先出(FIFO)的原则对元素进行排序。默认情况下不保证访问者公平的访问队列。熟悉ArrayBlockingQueue会知道,保证BlockingQueue线程安全是通过ReentrantLock保证的,ReentrantLock具有公平和非公平的模式,所以ArrayBlockingQueue也具有公平和非公平之分。

LinkedBlockingQueue

LinkedBlockingQueue是一个用链表实现的有界阻塞队列。此队列的默认和最大长度为Integer.MAX_VALUE。此队列按照先进先出的原则对元素进行排序。它和ArrayBlockingQueue是使用场景最对的阻塞队列。和ArrayBlockingQueue比较,LinkedBlockingQueue内部使用了两把锁保证线程的安全性,putLock和takeLock, 这也意味着在高并发的情况下生产者和消费者可以并行地操作队列中的数据,以此来提高整个队列的并发性能。

PriorityBlockingQueue

PriorityBlockingQueue是一个支持优先级的无界队列。默认情况下元素采取自然顺序排列,也可以通过比较器comparator来指定元素的排序规则。元素按照升序排列。虽然称作无界队列,PriorityBlockingQueue队列长度是根据需要逐渐增加的,默认队列长度是11,在队列长度64以内,队列长度不满足时,每次长度递增(oldsize+2)个。大于64则长度增加两倍(oldsize >>1)

DelayQueue

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

SynchronousQueue

一个没有数据缓冲的BlockingQueue,生产者线程对其的插入操作put必须等待消费者的移除操作take,反过来也一样。其功能完全可以由ArrayBlockingQueue来替代,内部并没有数据缓存空间,可以用来在线程间安全的交换单一元素,使用场景比较单一。优势可能就在于轻量级吧,由于没有缓存空间,采用了一种性能更好的无锁算法 — 扩展的“Dual stack and Dual queue”算法。

LinkedBlockingDeque

LinkedBlockingDeque是双向链表实现的双向并发阻塞队列。该阻塞队列列同时支持FIFO和FILO两种操作方式,即可以从队列的头和尾同时操作(插入/删除)。默认容量大小等于Integer.MAX_VALUE。

文章来源:智云一二三科技

文章标题:java并发包系列(九)-阻塞队列BlockingQueue

文章地址:https://www.zhihuclub.com/194748.shtml

关于作者: 智云科技

热门文章

网站地图