这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战
BlockingQueue简介
在讲ArrayBlockingQueue之前先讲一下阻塞队列,阻塞队列支持阻塞的插入和移除。即当队列满了的情况下,队列会阻塞插入元素的线程,直到队列不满;当队列为空的情况下,队列会阻塞获取元素的线程,直到队列非空。
BlockingQueue的核心方法
offer(anObject):表示如果可能的话,将anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则返回false。本方法不阻塞当前执行方法的线程
offer(E o, long timeout, TimeUnit unit):可以设定等待的时间,如果在指定的时间内,还不能往队列中加入BlockingQueue,则返回失败。
put(anObject):把anObject加到BlockingQueue里,如果BlockingQueue没有空间,则调用此方法的线程被阻断,直到BlockingQueue里面有空间再继续。
poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null。
poll(long timeout, TimeUnit unit):从BlockingQueue取出一个队首的对象,如果在指定时间内,队列一旦有数据可取,则立即返回队列中的数据。否则知道时间超时还没有数据可取,返回失败。
take():取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的数据被加入。
drainTo():一次性从BlockingQueue获取所有可用的数据对象(还可以指定获取数据的个数), 通过该方法,可以提升获取数据效率;不需要多次分批加锁或释放锁。
需要注意的是BlockingQueue不接受null值的插入,相应的方法在碰到null的插入时会抛出NullPointerException 异常。null值用于作为特殊值返回,代表poll失败。
常见的BlockingQueue:
ArrayBlockingQueue
ArrayBlockingQueue是一个用数组实现的有界阻塞队列。按照先进先出(FIFO)的原则对元素进行排序。有界是指它不能够存储无限多数量的元素,在创建ArrayBlockingQueue时,必须要给它指定一个队列的大小。阻塞指在添加/取走元素时,当队列没有空间/为空的时候会阻塞,知道队列有空间/有新的元素加入时再继续。因为采用的是循环数组的形式表达队列,所以队列的容量一旦在构造时指定,后续不能改变,对于数组的长度来说,根据初始化的参数为标准,类中没有默认的数组长度。
源码分析
重要属性
ArrayBlockingQueue的底层组包括:数组,一个重入锁,两个条件队列
1 | arduino复制代码//队列中元素保存的地方 |
构造方法
1 | csharp复制代码 |
重要方法
添加元素
add()方法:此方法,实际上调用了offer(e)方法。
1 | typescript复制代码public boolean add(E e) { |
offer(e)方法入队入参e为null,会抛空指针异常。
offer(E e)方法:将元素添加到 BlockingQueue 里,如果可以容纳返回 true 否则返回 false
1 | csharp复制代码public boolean offer(E e) { |
put(e)方法:将元素添加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻塞,直到有空间
1 | csharp复制代码public void put(E e) throws InterruptedException { |
enqueue(E x)入队,利用放指针循环使用数组来存储元素。
1 | ini复制代码private void enqueue(E x) { |
获取元素
poll()方法,取队头(首个)元素并删除,没有则返回null。
1 | csharp复制代码public E poll() { |
take()方法,如果队列中有元素,则获取并删除,如果没有元素,则阻塞等待
1 | csharp复制代码public E take() throws InterruptedException { |
dequeue()方法。
1 | ini复制代码private E dequeue() { |
peek()方法,只取不删,当队列中没有元素时会返回null。
1 | csharp复制代码public E peek() { |
删除元素
remove(o)方法,如果队列为空或者没有找到该元素返回false,否则删除元素并且返回true。
1 | ini复制代码public boolean remove(Object o) { |
removeAt(index)方法,删除指定位置上的元素
1 | ini复制代码void removeAt(final int removeIndex) { |
总结
ArrayBlockingQueue特点是不需要扩容,因为是初始化时指定容量,并利用takeIndex和putIndex循环利用数组。并且有重入锁和两个条件保证并发安全。
本文转载自: 掘金