ArrayBlockingQueue介绍

ArrayBlockingAQueue是用数组实现的线程安全的有界的阻塞队列。

线程安全是指通过“互斥锁”保护竞争资源,实现了对线程对竞争资源的互斥访问,有界是指ArrayB咯KingQueue对应的数组是有界限的,阻塞队列是指当多个线程访问竞争资源时,当竞争资源已经被某个线程获取时,其他要获取该线程的线程需要等待。

注意:ArrayBlockingQueue不同于LinkedBlockingQueue,ArrayBlockingQueue是数组实现的,并且是有界限的;而LinkedBlockingQueue是链表实现的,是无界限的。

ArrayBlokingQueue的uml图:

说明:

  1. ArrayBlockingQueue继承于AbstractQueue,并且它实现了BlockingQueue接口。
  2. ArrayBlockingQueue内部是通过Object[]数组保存数据的,也就是说ArrayBlockingQueue本质上是通过数组实现的。ArrayBlockingQueue的大小,即数组的容量是创建ArrayBlockingQueue时指定的。
  3. ArrayBlockingQueue与ReentrantLock是组合关系,ArrayBlockingQueue中包含一个ReentrantLock对象(lock)。ReentrantLock是可重入的互斥锁,ArrayBlockingQueue就是根据该互斥锁实现“多线程对竞争资源的互斥访问”。而且,ReentrantLock分为公平锁和非公平锁,关于具体使用公平锁还是非公平锁,在创建ArrayBlockingQueue时可以指定;而且,ArrayBlockingQueue默认会使用非公平锁。

  4. 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(一)相关推荐

  1. Java阻塞队列ArrayBlockingQueue和LinkedBlockingQueue实现原理分析

    转载自  Java阻塞队列ArrayBlockingQueue和LinkedBlockingQueue实现原理分析 Java中的阻塞队列接口BlockingQueue继承自Queue接口. Block ...

  2. JUC多线程:阻塞队列ArrayBlockingQueue与LinkedBlockingQueue

    一.什么是阻塞队列: 阻塞队列最大的特性在于支持阻塞添加和阻塞删除方法: 阻塞添加:当阻塞队列已满时,队列会阻塞加入元素的线程,直到队列元素不满时才重新唤醒线程执行加入元素操作. 阻塞删除:但阻塞队列 ...

  3. 有界阻塞队列ArrayBlockingQueue和无界阻塞队列LinkedBlockingQueue

    ArrayBlockingQueue和LinkedBlockingQueue最大的区别是一个是有界无界,各有优劣. 先看实例代码: main函数起2个线程模拟生成消费者 import java.uti ...

  4. 阻塞队列 java 源码_Java源码解析阻塞队列ArrayBlockingQueue常用方法

    本文基于jdk1.8进行分析 首先看一下ArrayBlockingQueue的成员变量.如下图.最主要的成员变量是items,它是一个Object类型的数组用于保存阻塞队列中的元素.其次是takeIn ...

  5. JUC队列-LinkedBlockingQueue(二)

    LinkedBlockingQueue介绍 LinkedBlockingQueue是一个以单向链表实现的阻塞队列,链表队列的吞吐量通常高于基于数组的队列,但是在大多数场景中,其可预见的性能要低. 要注 ...

  6. java 队列 array_Java源码解析阻塞队列ArrayBlockingQueue常用方法

    本文基于jdk1.8进行分析 首先看一下ArrayBlockingQueue的成员变量.如下图.最主要的成员变量是items,它是一个Object类型的数组用于保存阻塞队列中的元素.其次是takeIn ...

  7. JAVA可阻塞队列-ArrayBlockingQueue

    在前面的的文章,写了一个带有缓冲区的队列,是用JAVA的Lock下的Condition实现的,但是JAVA类中提供了这项功能,就是ArrayBlockingQueue, ArrayBlockingQu ...

  8. 队列阻塞_Java并发|阻塞队列ArrayBlockingQueue解析

    之前的文章我们学了 ConcurrentHashMap. ConcurrentLinkedQueue 等线程安全容器,而且也说了 Java并发包中的 Concurent 开头的并发容器都是非阻塞的,是 ...

  9. java队列,ArrayBlockingQueue

    2019独角兽企业重金招聘Python工程师标准>>> 提供了三个构造方法: ①.ArrayBlockingQueue(int capacity)//指定长度,默认加锁机制为非公平锁 ...

最新文章

  1. Kaggle机器学习入门实战 -- Titanic乘客生还预测
  2. [学习笔记]03.字符串的扩展
  3. SmartCode 使用常见问题
  4. Beetle在TCP通讯中使用协议分析器和自定义协议对象
  5. Java基础 Day04(个人复习整理)
  6. fatal: protocol error: bad line length character: No s原因
  7. 佛山高新区构建大数据产业新生态
  8. 如何安装vscode网页版_如何让用编辑器编写EverNote?
  9. C语言课程2——我们交流的工具:Coding.net
  10. K-th largest element in an array
  11. 怎么做好企业网站关键词优化
  12. 威联通文件传输服务器,威联通QTS文件传输体验
  13. 百度云安装mysql_mysql5.7 安装版本配置教程+百度云资源分享
  14. 1-1:Huawei路由交换技术简单知识
  15. 基于ETest的发动机ECU硬件在环测试平台的研究与开发
  16. 数据研发工程师面试全过程(个人面试)
  17. 使用go语言提取ins视频地址和图片地址
  18. dhcp显示否服务器怎么设置,怎么开启 dhcp服务器配置
  19. RK3568平台开发系列讲解(内核篇)内核Oops日志分析
  20. Mybatis之一个SQL的运行过程

热门文章

  1. MFC下CSocket编程详解
  2. Gh0st源码学习(一)前期准备工作
  3. Inno Setup 5制作安装程序
  4. Ubuntu 16.04 安装 Gazebo
  5. PyCairo 中的透明度
  6. 低至4.7折起!戴尔OptiPlex商用台式机限时特惠,重磅来袭!
  7. 睡前必读 | 如何系统性地学习分布式系统?
  8. 周末随笔 | 问好一个问题,有的放矢
  9. 【今晚七点半】:龙芯多媒体技术生态 从平台优化实践说起
  10. ffplay.c学习-5-视频输出和尺⼨变换