并发队列之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)进行插入操作.进行插入操作的端称为队尾,进行删除操作的端称为队头.队列中没有元素时,称为空队列. 在队列这 ...
随机推荐
- Yii2 框架下 session跨域共享互通
在项目实施过程中,往往把一个大项目进行分拆成几个独立的项目,项目用完全独立的域名和文件,可以放到不同的服务器上的独立分项目. 几个子项目共用一个登录点. 原理简单来说就是服务端session 共享, ...
- XSS 3
打开第三题然后会看到 然后进行一下添加数据 然后会发现数据被添加到 value=""双引号中然后然后我们会想到提前闭合 代码 然后进行编码 然后就可以通过了 此题与xss 2类似 ...
- 【代码总结】Struts2 Action接受参数方式的对比
一.属性方式 1.Action中:对应表单参数的setter.getter 2.页面中 :Form中元素name取值属性名 <s:property value="属性名" ...
- 将html代码部署到阿里云服务器,并进行域名解析,以及在部署过程中遇到的问题和解决方法
本博客主要是说一下,,如何将html代码部署到阿里云服务器,并进行域名解析,以及在部署过程中遇到的问题和解决方法. 1.先在阿里云上购买一台阿里云服务器(ECS云服务器): 2.远程连接上该服务器,在 ...
- opencv安装中的各种问题汇总
问题1:opencv-2.4.10/modules/gpu/src/nvidia/core/NCV.cu(356): error : namespace "std" has no ...
- 寒假安卓app开发学习记录(2)
今天属实是头疼的一天.开始的时候是简单了解了一下安卓的系统架构,了解到大概分为四个部分. 然后看了两节创建安卓项目的课程,准备去实践一下的时候突然发现我的eclipse里竟然没有Android选项.查 ...
- 使用Newtonsoft序列化对象,实现深拷贝
工作记录 深拷贝:全新创建一个对象,值与复制对象一致,两个对象互不相关,修改一个对象不会影响到另一个对象 浅拷贝:全新创建一个对象,值与复制对象一致,两个对象相关,修改一个对象影响到另一个对象 在工作 ...
- jmeter实现服务器端后台接口性能测试
实现目的 在进行服务器端后台接口性能测试时,需要连接到Linux服务器端,然后通过命令调用socket接口,这个过程就需要用到jmeter的SSH Command取样器实现了. 脚本实现 设置CSV ...
- 117. 填充每个节点的下一个右侧节点指针 II
Q: 给定一个二叉树 struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每个 next 指针,让这个指针指向其下一个右 ...
- 吴裕雄 python 神经网络——TensorFlow实现AlexNet模型处理手写数字识别MNIST数据集
import tensorflow as tf # 输入数据 from tensorflow.examples.tutorials.mnist import input_data mnist = in ...