并发队列之ArrayBlockingQueue
上一篇我们说了并发队列中的LinkedBlockingQueue队列,这次我们看看ArrayBlockingQueue,看看名字,我们想象一下LinkedList和ArrayList的区别,我们可以知道ArrayBlockingQueue底层肯定是基于数组实现的,这是一个有界数组;
ArrayBlockingQueue其中的组成部分和LinkedBlockingQueue及其相似,也是有两个条件变量,维护阻塞队列,实现了生产消费者模式;
一.简单认识ArrayBlockingQueue
先看看几个常用属性:
//数组用于存放队列元素
final Object[] items;
//出队索引
int takeIndex;
//入队索引
int putIndex;
//队列中元素数量
int count;
//独占锁
final ReentrantLock lock;
//如果数组中为空,还有线程取数据,就丢到这个条件变量中来阻塞
private final Condition notEmpty;
//队列满了,还有线程往数组中添加数据,就把线程丢到这里来阻塞
private final Condition notFull;
由于这是一个有界的数组,我们再看看构造器:
//指定容量,默认是非公平策略
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
//指定容量和独占锁的策略
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 ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) {
this(capacity, fair); final ReentrantLock lock = this.lock;
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
int i = 0;
try {
for (E e : c) {
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
二.offer方法
向队列尾部添加一个元素,添加成功就返回true,队列满了就丢掉当前元素直接返回false,方法不阻塞;
public boolean offer(E e) {
//非空检验
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
//如果数组中实际数量和最大容量相等,添加失败,返回false
if (count == items.length)
return false;
else {
//添加成功,方法实现在下面
enqueue(e);
return true;
}
} finally {
//释放锁
lock.unlock();
}
}
private void enqueue(E x) {
//拿到数组
final Object[] items = this.items;
//在putIndex这个位置放入数据x,然后把putIndex加一,说明这个参数表示的是下一个数据要放入的位置的索引
items[putIndex] = x;
//这里putIndex是先加一然后再比较是否相等,比如这里数组的最大容量是5,那么索引的最大值应该是4,而如果putIndex等于5了,说明数组
//越界了,加把这个索引重置为0
if (++putIndex == items.length)
putIndex = 0;
count++;
//添加完成之后,说明了数组中有数据了,这里会唤醒之前因为去数组中取数据而阻塞的线程
notEmpty.signal();
}
三.put方法
向队列尾部插入一个元素,队列有空闲就插入成功返回true,队列满了就阻塞当前线程到notFull的条件队列中,等有空闲之后就会被唤醒;阻塞过程中对中断会有响应的;
public void put(E e) throws InterruptedException {
//非空检查
checkNotNull(e);
final ReentrantLock lock = this.lock;
//注意该锁的获取方式
lock.lockInterruptibly();
try {
//如果线程满了,就把当前线程放到notFull条件变量的阻塞队列中
while (count == items.length)
notFull.await();
//没有满,就添加数据
enqueue(e);
} finally {
//释放锁
lock.unlock();
}
}
四.poll方法
头部获取并移除一个元素,如果队列为空,就返回null,方法不阻塞;
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//如果队列为空,就返回null
//如果队列不为空,就调用dequeue方法获取并删除队列头部的元素
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
private E dequeue() {
//获取数组
final Object[] items = this.items;
@SuppressWarnings("unchecked")
//获取takeIndex位置的元素,最后会将这个返回
E x = (E) items[takeIndex];
//然后将takeInde位置置为空
items[takeIndex] = null;
//如果takeIndex已经是数组的最后一个位置了,就将takeIndex重置为0
if (++takeIndex == items.length)
takeIndex = 0;
//实际数量减一
count--;
if (itrs != null)
itrs.elementDequeued();
//唤醒notFull中线程
notFull.signal();
return x;
}
五.take方法
获取并删除当前队列头部的元素,如果队列为空当前线程阻塞直到被唤醒,对中断有响应;
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
//可中断的方式获取锁
lock.lockInterruptibly();
try {
//如果数组为空,此时就唤醒notEmpty中条件队列里的线程
while (count == 0)
notEmpty.await();
//获取并删除头节点
return dequeue();
} finally {
lock.unlock();
}
}
六.peek方法
只是获取头部元素,不删除,如果队列为空就返回null,这个方法是线程不阻塞的
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return itemAt(takeIndex); // null when queue is empty
} finally {
lock.unlock();
}
}
//获取到数组中索引为takeIndex中的数据
@SuppressWarnings("unchecked")
final E itemAt(int i) {
return (E) items[i];
}
七.总结
理解了上一篇博客中说的LinkedBlockingQueue,那么再看这一篇其实太容易了,就是操作数组嘛!用下面这个图表示:

并发队列之ArrayBlockingQueue的更多相关文章
- 并发队列:ArrayBlockingQueue实际运用场景和原理
ArrayBlockingQueue实际应用场景 之前在某公司做过一款情绪识别的系统,这套系统通过调用摄像头接口采集人脸信息,将采集的人脸信息做人脸识别和情绪分析,最终经过一定的算法将个人情绪数据转化 ...
- 10.并发包阻塞队列之ArrayBlockingQueue
上一节中对并发包中的非阻塞队列ConcurrentLinkedQueue的入队.出队做了一个简要的分析,本文将对并发包中的阻塞队列做一个简要分析. Java并发包中的阻塞队列一共7个,当然他们都是线程 ...
- 并发编程(九)—— Java 并发队列 BlockingQueue 实现之 LinkedBlockingQueue 源码分析
LinkedBlockingQueue 在看源码之前,通过查询API发现对LinkedBlockingQueue特点的简单介绍: 1.LinkedBlockingQueue是一个由链表实现的有界队列阻 ...
- 并发队列ConcurrentLinkedQueue、阻塞队列AraayBlockingQueue、阻塞队列LinkedBlockingQueue 区别和使用场景总结
三者区别与联系: 联系,三者 都是线程安全的.区别,就是 并发 和 阻塞,前者为并发队列,因为采用cas算法,所以能够高并发的处理:后2者采用锁机制,所以是阻塞的.注意点就是前者由于采用cas算 ...
- 并发包阻塞队列之ArrayBlockingQueue
并发包阻塞队列之ArrayBlockingQueue jdk1.7.0_79 上一节中对并发包中的非阻塞队列ConcurrentLinkedQueue的入队.出队做了一个简要的分析,本文将对并发 ...
- JAVA多线程(二) 并发队列和阻塞队列
github代码地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/spb-brian-query-service/ ...
- Java深入学习(2):并发队列
并发队列: 在并发队列中,JDK有两套实现: ConcurrentLinkedQueue:非阻塞式队列 BlockingQueue:阻塞式队列 阻塞式队列非阻塞式队列的区别: 阻塞式队列入列操作的时候 ...
- 【Java并发】并发队列与线程池
并发队列 阻塞队列与非阻塞队 ConcurrentLinkedQueue BlockingQueue ArrayBlockingQueue LinkedBlockingQueue PriorityBl ...
- 并发队列 ConcurrentLinkedQueue 及 BlockingQueue 接口实现的四种队列
队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作.进行插入操作的端称为队尾,进行删除操作的端称为队头.队列中没有元素时,称为空队列. 在队列这 ...
随机推荐
- v:bind指令对于传boolean值的注意之处
1,
- wampserver apache 403无权限访问 You don't have permission to access /index.html on this server
今天接到要求 需要配置一下https 折腾好久 最后好还遇到了权限不够的问题 最后解决方案如下 我这边补充一下我的方法 我的apache是 2.4.23 版本 是由 wampserver集成的 在 h ...
- Vue集成openlayers
1.安装ol库 使用cnpm i ol -s命令安装 2.建一个olMap.vue文件夹 <template> <div class='olMap'> <h2>{{ ...
- Unity UGUI事件接口概述
UGUI 系统虽然提供了很多封装好的组件,但是要实现一些特定的功能还是显得非常有限,这时候就需要使用事件接口来完成UI功能的实现.比如我们想实现鼠标移动到图片上时自动显示图片的文字介绍,一般思路会想到 ...
- Jquery插件validate使用一则
jquery.validate是一个基于jquery的非常优秀的验证框架,可以通过它迅速验证一些常见的输入,并且可以自己扩充自己的验证方法. 主要功能有: 验证url,email,number,len ...
- Centos6.10-FastDFS-Tracker.conf示例配置
Centos610系列配置 FastDFS_Tracker.conf示例配置 # is this config file disabled # false for enabled # true for ...
- 如何安装和使用Maven
今天我们来学习一下如何安装Maven,把步骤分享给大家,希望能对大家有帮助! 我的博客地址:https://www.cnblogs.com/themysteryofhackers/p/11996550 ...
- Angular的启动过程
我们知道由命令 ng new project-name,cli将会创建一个基础的angular应用,我们是可以直接运行起来一个应用.这归功与cli已经给我们创建好了一个根模块AppModule,而根模 ...
- VS Code的git配置
最近打算使用VS Code作为python的编辑器,这里记录一下VS Code中git的配置方法 因为vscode中git只是使用本地的git,所以本地必须先安装git才行. 1.git的安装 git ...
- 巨头环伺下,青云QingCloud的云计算之路危机重重
编辑 | 于斌 出品 | 于见(mpyujian) 随着互联网.科技行业的深入发展,国内云计算市场正越来越爆发出惊人的潜力,大量大.中.小型玩家开始不断发力,涌现出了一大批增速明显的行业玩家. 以BA ...