时间:2021-05-19
阻塞队列(BlockingQueue)首先是一个支持先进先出的队列,与普通的队列完全相同;
其次是一个支持阻塞操作的队列,即:
阻塞队列用在多线程的场景下,因此阻塞队列使用了锁机制来保证同步,这里使用的可重入锁;
而对于阻塞与唤醒机制则有与锁绑定的Condition实现
应用场景:生产者消费者模式
java中的阻塞队列根据容量可以分为有界队列和无界队列:
java8中提供了7种阻塞队列阻塞队列供开发者使用,如下表: 类名 描述 ArrayBlockingQueue 一个由数组结构组成的有界阻塞队列 LinkedBlockingQueue 由链表结构组成的有界阻塞队列(默认大小Integer.MAX_VALUE) PriorityBlockingQueue 支持优先级排序的无界阻塞队列 DelayQueue 使用优先级队列实现的延迟无界阻塞队列 SynchronousQueue 不存储元素的阻塞队列,即单个元素的队列 LinkedTransferQueue 由链表结构组成的无界阻塞队列 LinkedBlockingDeque 由链表结构组成的双向阻塞队列
另外还有一个在ScheduledThreadPoolExecutor中实现的DelayedWorkQueue阻塞队列,
但这个阻塞队列开发者不能使用。它们之间的UML类图如下图:
BlockingQueue接口是阻塞队列对外的访问接口,所有的阻塞队列都实现了BlockQueue中的方法
作为一个队列的核心方法就是入队和出队。由于存在阻塞策略,BlockQueue将出队入队的情况分为了四组,每组提供不同的方法:
对于每种情况BlockingQueue提供的方法如下表:
方法\处理方式 抛出异常 返回特定值(布尔值) 一直阻塞 超时退出 插入 add(e) offer(e) put(e) offer(e,time,unit) 移除 remove() poll() take() poll(time.unit) 检查 element() peek() 不可用 不可用
上述方法一般用于生产者-消费者模型中,是其中的生产和消费操作队列的核心方法。
除了这些方法,BlockingQueue还提供了一些其他的方法如下表:
方法名称 描述 remove(Object o) 从队列中移除一个指定值 size() 获取队列中元素的个数 contains(Object o) 判断队列是否包含指定的元素,但是这个元素在这次判断完可能就会被消费 drainTo(Collection<? super E> c) 将队列中元素放在给定的集合中,并返回添加的元素个数 drainTo(Collection<? super E> c, int maxElements) 将队列中元素取maxElements(不超过队列中元素个数)个放在给定的集合中,并返回添加的元素个数 remainingCapacity() 计算队列中还可以存放的元素个数 toArray() 以objetc数组的形式获取队列中所有的元素 toArray(T[] a) 以给定类型数组的方式获取队列中所有的元素 clear() 清空队列,危险的操作
阻塞队列的实现依靠通知模式实现:当生产者向满了的队列中添加元素时,会阻塞住生产者,
直到消费者消费了一个队列中的元素后会通知消费者队列可用,此时再由生产者向队列中添加元素。反之亦然。
阻塞队列的阻塞唤醒依靠Condition——条件队列来实现。
以ArrayBlockingQueue为例说明:
ArrayBlockingQueue的定义:
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable { /** The queued items */ //以数组的结构存储队列的元素,采用的是循环数组 final Object[] items; /** items index for next take, poll, peek or remove */ //队列的队头索引 int takeIndex; /** items index for next put, offer, or add */ //队列的队尾索引 int putIndex; /** Number of elements in the queue */ //队列中元素的个数 int count; /** Main lock guarding all access */ //对于ArrayBlockingQueue所有的操作都需要加锁, final ReentrantLock lock; /** Condition for waiting takes */ //条件队列,当队列为空时阻塞消费者并在生产者生产后唤醒消费者 private final Condition notEmpty; /** Condition for waiting puts */ //条件队列,当队列满时阻塞生产者,并在消费者消费队列后唤醒生产者 private final Condition notFull;}根据类的定义字段可以看到,有两个Condition条件队列,猜测以下过程
向队列中添加元素put()方法的添加过程。
/** * 向队列中添加元素 * 当队列已满时需要阻塞当前线程 * 放入元素后唤醒因队列为空阻塞的消费者 */ public void put(E e) throws InterruptedException { checkNotNull(e); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { //当队列已满时需要notFull.await()阻塞当前线程 //offer(e,time,unit)方法就是阻塞的时候加了超时设定 while (count == items.length) notFull.await(); //放入元素的过程 enqueue(e); } finally { lock.unlock(); } } /**enqueue实际添加元素的方法*/ private void enqueue(E x) { // assert lock.getHoldCount() == 1; // assert items[putIndex] == null; final Object[] items = this.items; items[putIndex] = x; if (++putIndex == items.length) putIndex = 0; count++; //如果条件队列中存在等待的线程 //唤醒 notEmpty.signal(); }从队列中获取元素take()方法的获取过程。
/** * 从队列中获取元素 * 当队列已空时阻塞当前线程 * 从队列中消费元素后唤醒等待的生产线程 */ public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { //队列为空需要阻塞当前线程 while (count == 0) notEmpty.await(); //获取元素的过程 return dequeue(); } finally { lock.unlock(); } } /**dequeue实际消费元素的方法*/ private E dequeue() { // assert lock.getHoldCount() == 1; // assert items[takeIndex] != null; final Object[] items = this.items; @SuppressWarnings("unchecked") E x = (E) items[takeIndex]; items[takeIndex] = null; if (++takeIndex == items.length) takeIndex = 0; count--; if (itrs != null) itrs.elementDequeued(); //消费元素后从唤醒阻塞的生产者线程 notFull.signal(); return x; }阻塞队列提供了不同于普通队列的增加、删除元素的方法,核心在与队列满时阻塞生产者和队列空时阻塞消费者。
这一阻塞过程依靠与锁绑定的Condition对象实现。Condition接口的实现在AQS中实现,具体的实现类是
ConditionObject
以上就是详解java中的阻塞队列的详细内容,更多关于java 阻塞队列的资料请关注其它相关文章!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
c++链表实现的阻塞队列最近从java源码里发现了阻塞队列的实现,觉得非常有趣。首先,介绍下什么是阻塞队列。阻塞队列代表着一个队列可以线程安全的往该队列中写数据
本文基于jdk1.8进行分析。阻塞队列是java开发时常用的一个数据结构。首先看一下阻塞队列的作用是什么。阻塞队列的作用,从源码中类的注释中来了解,是最清晰准确
今天重温了下java多线程中的notify()方法以及wait()方法,一时兴起,决定通过这俩个方法,实现一个简易的自定义阻塞队列。阻塞队列是什么,与普通队列的
Java的阻塞队列,在实现时,使用到了lock和condition,下面是对其主要方法的介绍。首先看一下,阻塞队列中使用到的锁。/**Mainlockguard
这篇文章主要介绍了java阻塞队列实现原理及实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下阻塞队列与