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. Elasticsearch倒排索引结构

    一切设计都是为了提高搜索的性能 倒排索引(Inverted Index)也叫反向索引,有反向索引必有正向索引.通俗地来讲,正向索引是通过key找value,反向索引则是通过value找key. 先来回 ...

  2. Python3+unitest自动化测试初探(上篇)

    目录 1.概念介绍 2.准备工作 3.一个简单的例子 4.test fixture 5.测试套 1.概念介绍 unit test:单元测试,可以简单粗暴地理解成用一段代码去测试另外一段代码.unitt ...

  3. C#语法——元组类型

     元组Tuple   我们现在使用的C#语法已经可以满足日常的开发需求,但C#语法还在进行版本的更新,在创造更多更优秀的语义来让我们使用.这里介绍一下C#5.0里的提供的语法——元组. 在C#中定义T ...

  4. GitHub 可以免费创建私人仓库啦

    如果你不知道什么是 GitHub,也可以往下看,只不过可能感受不会那么深啦. 昨天,GitHub 博客发表了文章 其中比较重要的已经用蓝色线标注了. GitHub 支持开发者创建免费私人仓库,但是需要 ...

  5. nginx rewrite 实现URL跳转

    最近工作中常常要改nginx配置,学习了nginx中rewrite的用法 URL跳转这里说的URL跳转就是用户在访问一个URL时将其跳转到另一个URL上.常见的应用场景是让多个域名跳转到同一个URL上 ...

  6. SQLServer事务在C#当中的应用

    1:事务是什么 事务指的是一系列SQL操作的逻辑工作单元,,要么完全地执行,要么完全地不执行. 一个逻辑工作单元必须有4个属性,原子性(Atomic).一致性(Consistent).隔离型(Isol ...

  7. 学JAVA第十七天,接口与抽象方法

    JAVA接口可以让代码更加有合理的规范性,就想一个项目小组,组长要负责把成员的代码整合,但是每个成员写的方式都是按照他们自己的想法来写的, 所以,整合起来就非常麻烦. 但是,如果我们的组长制作了一个接 ...

  8. 初学Shiro

    Shiro Shiro是什么? Apache Shiro是Java的一个安全(权限)框架. Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境下,也可以用者JavaEE环境下 ...

  9. Dynamics 365-为什么查到的Record的Id是Guid初始值

    通过代码查询CRM数据,这个是开发经常会碰到的情况,获取返回的EntityCollection之后,我们会拿Entity.Id做进一步操作.笔者最近碰到的情况,是Entity.Id是个初始值.先上一段 ...

  10. row_number() over()分页查询

    1.首先讲下row_number() over() 是干什么的? 是一个分析函数,会在数据表生成一个排序列. 案例SQL: select ROW_NUMBER() over(order by book ...