JUC队列-ArrayBlockingQueue(一)
ArrayBlockingQueue介绍
ArrayBlockingAQueue是用数组实现的线程安全的有界的阻塞队列。
线程安全是指通过“互斥锁”保护竞争资源,实现了对线程对竞争资源的互斥访问,有界是指ArrayB咯KingQueue对应的数组是有界限的,阻塞队列是指当多个线程访问竞争资源时,当竞争资源已经被某个线程获取时,其他要获取该线程的线程需要等待。
注意:ArrayBlockingQueue不同于LinkedBlockingQueue,ArrayBlockingQueue是数组实现的,并且是有界限的;而LinkedBlockingQueue是链表实现的,是无界限的。
ArrayBlokingQueue的uml图:
说明:
- ArrayBlockingQueue继承于AbstractQueue,并且它实现了BlockingQueue接口。
- ArrayBlockingQueue内部是通过Object[]数组保存数据的,也就是说ArrayBlockingQueue本质上是通过数组实现的。ArrayBlockingQueue的大小,即数组的容量是创建ArrayBlockingQueue时指定的。
ArrayBlockingQueue与ReentrantLock是组合关系,ArrayBlockingQueue中包含一个ReentrantLock对象(lock)。ReentrantLock是可重入的互斥锁,ArrayBlockingQueue就是根据该互斥锁实现“多线程对竞争资源的互斥访问”。而且,ReentrantLock分为公平锁和非公平锁,关于具体使用公平锁还是非公平锁,在创建ArrayBlockingQueue时可以指定;而且,ArrayBlockingQueue默认会使用非公平锁。
ArrayBlockingQueue与Condition是组合关系,ArrayBlockingQueue中包含两个Condition对象(notEmpty和notFull)。而且,Condition又依赖于ArrayBlockingQueue而存在,通过Condition可以实现对ArrayBlockingQueue的更精确的访问。
ArrayBlockingQueue源码分析
构造方法
public ArrayBlockingQueue(int capacity, boolean fair) {if (capacity <= 0)throw new IllegalArgumentException();this.items = new Object[capacity];lock = new ReentrantLock(fair);notEmpty = lock.newCondition();notFull = lock.newCondition();
}
初始化数组,独占锁和两个“条件”,非空条件和满条件。
添加元素
public void put(E e) throws InterruptedException {checkNotNull(e);//获取队列的独占锁final ReentrantLock lock = this.lock;//获取锁,如果锁处于中断状态,则抛出InterruptedException异常lock.lockInterruptibly();try {//如果队列已满,则一直等待while (count == items.length)notFull.await();//入队enqueue(e);} finally {//释放锁lock.unlock();}}
说明:put(E e)的作用是将e插入阻塞队列的尾部。如果队列已满,则等待;否则,插入元素。
在了解入队enqueue操作时,我们先了解下面几个成员的含义:
// 队列中的元素个数
int takeIndex;
// 下一个被取出元素的索引
int putIndex;
// 下一个被添加元素的索引
int count;
enqueue()的源码如下:
private void enqueue(E x) {final Object[] items = this.items;//添加到队列中items[putIndex] = x;//设置下一个被取出元素的索引if (++putIndex == items.length)putIndex = 0;count++;//唤醒notEmpty上的等待线程notEmpty.signal();}
取出元素
取出元素的过程其实跟添加元素的过程,这里就直接贴出代码:
public E take() throws InterruptedException {// 获取“队列的独占锁”final ReentrantLock lock = this.lock;// 获取“锁”,若当前线程是中断状态,则抛出InterruptedException异常lock.lockInterruptibly();try {// 若“队列为空”,则一直等待。while (count == 0)notEmpty.await();// 取出元素return extract();} finally {// 释放“锁”lock.unlock();}
}
private E extract() {final Object[] items = this.items;// 强制将元素转换为“泛型E”E x = this.<E>cast(items[takeIndex]);// 将第takeIndex元素设为null,即删除。同时,帮助GC回收。items[takeIndex] = null;// 设置“下一个被取出元素的索引”takeIndex = inc(takeIndex);// 将“队列中元素数量”-1--count;// 唤醒notFull上的等待线程。notFull.signal();return x;
}
删除元素
这里我拿remove(Object o) 举例
public boolean remove(Object o) {if (o == null) return false;final Object[] items = this.items;final ReentrantLock lock = this.lock;lock.lock();try {if (count > 0) {final int putIndex = this.putIndex;int i = takeIndex;do {if (o.equals(items[i])) {removeAt(i);return true;}//索引到了末尾,重置0if (++i == items.length)i = 0;//直到 i = takeIndex增长到putIndex} while (i != putIndex);}return false;} finally {lock.unlock();}}
说明:remove(Object)实际上就是对数组的进行遍历对比,只不过这个队列数组有点特殊,它是环状的数组,也就是可重用的数组,如果找到该元素,调用removeAt()
void removeAt(final int removeIndex) {final Object[] items = this.items;//如果remove的索引时队列中的第一个元素,可以直接出队。if (removeIndex == takeIndex) {// removing front item; just advanceitems[takeIndex] = null;if (++takeIndex == items.length)takeIndex = 0;count--;if (itrs != null)itrs.elementDequeued();//如果remove的不是第一个元素,那么直接从reomve//的那个索引开始,后面的元素全部前移一位} else {// an "interior" remove// slide over all others up through putIndex.final int putIndex = this.putIndex;for (int i = removeIndex;;) {int next = i + 1;if (next == items.length)next = 0;if (next != putIndex) {items[i] = items[next];i = next;} else {items[i] = null;this.putIndex = i;break;}}count--;if (itrs != null)itrs.removedAt(removeIndex);}notFull.signal();}
JUC队列-ArrayBlockingQueue(一)相关推荐
- Java阻塞队列ArrayBlockingQueue和LinkedBlockingQueue实现原理分析
转载自 Java阻塞队列ArrayBlockingQueue和LinkedBlockingQueue实现原理分析 Java中的阻塞队列接口BlockingQueue继承自Queue接口. Block ...
- JUC多线程:阻塞队列ArrayBlockingQueue与LinkedBlockingQueue
一.什么是阻塞队列: 阻塞队列最大的特性在于支持阻塞添加和阻塞删除方法: 阻塞添加:当阻塞队列已满时,队列会阻塞加入元素的线程,直到队列元素不满时才重新唤醒线程执行加入元素操作. 阻塞删除:但阻塞队列 ...
- 有界阻塞队列ArrayBlockingQueue和无界阻塞队列LinkedBlockingQueue
ArrayBlockingQueue和LinkedBlockingQueue最大的区别是一个是有界无界,各有优劣. 先看实例代码: main函数起2个线程模拟生成消费者 import java.uti ...
- 阻塞队列 java 源码_Java源码解析阻塞队列ArrayBlockingQueue常用方法
本文基于jdk1.8进行分析 首先看一下ArrayBlockingQueue的成员变量.如下图.最主要的成员变量是items,它是一个Object类型的数组用于保存阻塞队列中的元素.其次是takeIn ...
- JUC队列-LinkedBlockingQueue(二)
LinkedBlockingQueue介绍 LinkedBlockingQueue是一个以单向链表实现的阻塞队列,链表队列的吞吐量通常高于基于数组的队列,但是在大多数场景中,其可预见的性能要低. 要注 ...
- java 队列 array_Java源码解析阻塞队列ArrayBlockingQueue常用方法
本文基于jdk1.8进行分析 首先看一下ArrayBlockingQueue的成员变量.如下图.最主要的成员变量是items,它是一个Object类型的数组用于保存阻塞队列中的元素.其次是takeIn ...
- JAVA可阻塞队列-ArrayBlockingQueue
在前面的的文章,写了一个带有缓冲区的队列,是用JAVA的Lock下的Condition实现的,但是JAVA类中提供了这项功能,就是ArrayBlockingQueue, ArrayBlockingQu ...
- 队列阻塞_Java并发|阻塞队列ArrayBlockingQueue解析
之前的文章我们学了 ConcurrentHashMap. ConcurrentLinkedQueue 等线程安全容器,而且也说了 Java并发包中的 Concurent 开头的并发容器都是非阻塞的,是 ...
- java队列,ArrayBlockingQueue
2019独角兽企业重金招聘Python工程师标准>>> 提供了三个构造方法: ①.ArrayBlockingQueue(int capacity)//指定长度,默认加锁机制为非公平锁 ...
最新文章
- Kaggle机器学习入门实战 -- Titanic乘客生还预测
- [学习笔记]03.字符串的扩展
- SmartCode 使用常见问题
- Beetle在TCP通讯中使用协议分析器和自定义协议对象
- Java基础 Day04(个人复习整理)
- fatal: protocol error: bad line length character: No s原因
- 佛山高新区构建大数据产业新生态
- 如何安装vscode网页版_如何让用编辑器编写EverNote?
- C语言课程2——我们交流的工具:Coding.net
- K-th largest element in an array
- 怎么做好企业网站关键词优化
- 威联通文件传输服务器,威联通QTS文件传输体验
- 百度云安装mysql_mysql5.7 安装版本配置教程+百度云资源分享
- 1-1:Huawei路由交换技术简单知识
- 基于ETest的发动机ECU硬件在环测试平台的研究与开发
- 数据研发工程师面试全过程(个人面试)
- 使用go语言提取ins视频地址和图片地址
- dhcp显示否服务器怎么设置,怎么开启 dhcp服务器配置
- RK3568平台开发系列讲解(内核篇)内核Oops日志分析
- Mybatis之一个SQL的运行过程