ArrayBlockingQueue是一个基于数组实现的有界的阻塞队列。

属性

    //底层存储元素的数组。为final说明一旦初始化,容量不可变,所以是有界的。
final Object[] items; //下一个take, poll, peek or remove操作的index位置
int takeIndex; //下一个put, offer, or add操作的index位置
int putIndex; // 元素数量
int count; /**
* 用于并发控制:使用经典的双Condition算法
*/
final ReentrantLock lock;
/** 获取操作等待条件 */
private final Condition notEmpty;
/** 插入操作等待条件 */
private final Condition notFull;

添加操作

1.add操作(不常用)

add()是最原始的方法。当队列满时,会抛出IllegalStateException。

    public boolean add(E e) {
return super.add(e);
} // 父类AbstractQueue中的add()
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}

2.offer操作

offer有两个版本。
不带超时版本:队列满时,直接返回false。
带超时版本:队列满时,阻塞直到队列可用。

    public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
//队列已满,直接返回false
if (count == items.length)
return false;
else {//未满,则插入元素
insert(e);
return true;
}
} finally {
lock.unlock();
}
} /**offer,带超时版本**/
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException { checkNotNull(e);
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
//可中断加锁
lock.lockInterruptibly();
try {
//不停判断是否满了
while (count == items.length) {
//超时,则直接返回false
if (nanos <= 0)
return false;
//队列已满,则等待
nanos = notFull.awaitNanos(nanos);
}
//阻塞直到队列可用,则插入元素
insert(e);
return true;
} finally {
lock.unlock();
}
}

3.put操作

    public void put(E e) throws InterruptedException {
//检查参数是否为null。为null则抛异常
checkNotNull(e);
final ReentrantLock lock = this.lock;
//加锁。可中断
lock.lockInterruptibly();
try {
//队列已满则一直等待,直到队列有可用空间
while (count == items.length)
notFull.await();//等待
//队列空闲时,插入元素
insert(e);
} finally {
//释放锁
lock.unlock();
}
}

删除操作

1.poll操作

    public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : extract();
} finally {
lock.unlock();
}
} private E extract() {
final Object[] items = this.items;
E x = this.<E>cast(items[takeIndex]);//强转
//删除
items[takeIndex] = null;
takeIndex = inc(takeIndex);
--count;
//通知
notFull.signal();
return x;
} /**poll,带超时版本**/
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
return extract();
} finally {
lock.unlock();
}
}

2.take操作

    public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return extract();
} finally {
lock.unlock();
}
}

3.peek操作

    public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : itemAt(takeIndex);
} finally {
lock.unlock();
}
}

清空操作

    public void clear() {
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
//依次将所有元素设为null
for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
items[i] = null;
//count,putIndex,takeIndex都为0
count = 0;
putIndex = 0;
takeIndex = 0; notFull.signalAll();
} finally {
lock.unlock();
}
}

总结

BlockingQueue接口提供了3个添加元素方法。

  • add:添加元素到队列里,添加成功返回true,如果队列已满则抛出IllegalStateException异常。不常用。
  • offer:添加元素到队列里,添加成功返回true,如果队列已满添加失败,返回false
  • put:添加元素到队列里,添加成功返回true,如果队列已满则阻塞直到队列可用

同时,BlockingQueue接口提供了3个获取(并删除)元素的方法。

  • remove:
  • poll:返回队列头部元素。队列为空时,返回null
  • take:队列为空时,会阻塞直到有数据加入到队列中

ArrayBlockingQueue源码分析的更多相关文章

  1. java多线程系列(九)---ArrayBlockingQueue源码分析

    java多线程系列(九)---ArrayBlockingQueue源码分析 目录 认识cpu.核心与线程 java多线程系列(一)之java多线程技能 java多线程系列(二)之对象变量的并发访问 j ...

  2. 死磕 java集合之ArrayBlockingQueue源码分析

    问题 (1)ArrayBlockingQueue的实现方式? (2)ArrayBlockingQueue是否需要扩容? (3)ArrayBlockingQueue有什么缺点? 简介 ArrayBloc ...

  3. 并发编程(八)—— Java 并发队列 BlockingQueue 实现之 ArrayBlockingQueue 源码分析

    开篇先介绍下 BlockingQueue 这个接口的规则,后面再看其实现. 阻塞队列概要 阻塞队列与我们平常接触的普通队列(LinkedList或ArrayList等)的最大不同点,在于阻塞队列的阻塞 ...

  4. Java并发编程笔记之ArrayBlockingQueue源码分析

    JDK 中基于数组的阻塞队列 ArrayBlockingQueue 原理剖析,ArrayBlockingQueue 内部如何基于一把独占锁以及对应的两个条件变量实现出入队操作的线程安全? 首先我们先大 ...

  5. 多线程高并发编程(12) -- 阻塞算法实现ArrayBlockingQueue源码分析(1)

    一.前言 前文探究了非阻塞算法的实现ConcurrentLinkedQueue安全队列,也说明了阻塞算法实现的两种方式,使用一把锁(出队和入队同一把锁ArrayBlockingQueue)和两把锁(出 ...

  6. Java核心复习——J.U.C ArrayBlockingQueue源码分析

    介绍 依赖关系 源码 构造方法 public ArrayBlockingQueue(int capacity) { this(capacity, false);//默认构造非公平的有界队列 } pub ...

  7. ArrayBlockingQueue 源码分析

    ArrayBlockingQueue ArrayBlockingQueue 能解决什么问题?什么时候使用 ArrayBlockingQueue? 1)ArrayBlockingQueue 是底层由数组 ...

  8. 【JUC】JDK1.8源码分析之ArrayBlockingQueue(三)

    一.前言 在完成Map下的并发集合后,现在来分析ArrayBlockingQueue,ArrayBlockingQueue可以用作一个阻塞型队列,支持多任务并发操作,有了之前看源码的积累,再看Arra ...

  9. JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue

    JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue 目的:本文通过分析JDK源码来对比ArrayBlockingQueue 和LinkedBlocki ...

随机推荐

  1. 使用描述符实现property功能

    # Author : Kelvin # Date : 2019/1/25 14:46 class Decproperty: def __init__(self, func): self.func = ...

  2. python接口自动化(三)--如何设计接口测试用例(详解)

    简介 上篇我们已经介绍了什么是接口测试和接口测试的意义.在开始接口测试之前,我们来想一下,如何进行接口测试的准备工作.或者说,接口测试的流程是什么?有些人就很好奇,接口测试要流程干嘛?不就是拿着接口文 ...

  3. 【Android Studio安装部署系列】三十四、将Eclipse项目导入到Android Studio中

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 我采用的是笨方法:新创建Android Studio项目,然后将Eclipse项目中的目录一一复制到Android Studio项目 ...

  4. Java进阶篇设计模式之三 ----- 建造者模式和原型模式

    前言 在上一篇中我们学习了工厂模式,介绍了简单工厂模式.工厂方法和抽象工厂模式.本篇则介绍设计模式中属于创建型模式的建造者模式和原型模式. 建造者模式 简介 建造者模式是属于创建型模式.建造者模式使用 ...

  5. 流水车间调度算法分析的简单+Leapms实践--混合整数规划的启发式建模

    流水车间调度算法分析的简单+Leapms实践--混合整数规划的启发式建模 清华大学出版社出版的白丹宇教授著作<流水车间与开放车间调度算法渐近分析>采用渐近分析方法分析多个NP-难类启发调度 ...

  6. Python input保证输入为int类型

    t = float(input("t(℃)="))

  7. Form 表单提交的几种方式

    简单的总结一下form表单提交的几种方式:1.最简单的方式 就用form的submit提交方式,这种提交方式是不需要回调函数的   这种方式最近到一个form提供action路径后台接受就可以< ...

  8. .NET CAD二次开发学习 直线画矩形并转换成组

    主要代码: using System;using System.Collections.Generic;using System.Linq;using System.Text;using System ...

  9. 并发concurrent---2

    背景:并发知识是一个程序员段位升级的体现,同样也是进入BAT的必经之路,有必要把并发知识重新梳理一遍. 并发concurrent: 使用ThreadLocal可以实现线程范围内共享变量,线程A写入的值 ...

  10. 1.常用turtle功能函数

    #turtle常用命令汇总,括号中的参数仅仅作为举例使用,可根据需要修改 #设置画面背景色 turtle.bgcolor("black") #设置窗口大小和在屏幕上的坐标 turt ...