功能简介:
  • ArrayBlockingQueue是一种基于数组实现的有界的阻塞队列。队列中的元素遵循先入先出(FIFO)的规则。新元素插入到队列的尾部,从队列头部取出元素。
  • 和普通队列有所不同,该队列支持阻塞操作。比如从空队列中取元素,会导致当前线程阻塞,直到其他线程将元素放入队列;将元素插入已经满的队列,同样会导致当前线程阻塞,直到其他线程从队列中取出元素。
  • ArrayBlockingQueue也支持公平和非公平策略(针对队列中元素的存取线程,也可认为是元素的生产者和消费者)。
源码分析:
  • ArrayBlockingQueue继承了AbstractQueue并实现了BlockingQueue,AbstractQueue是Queue的公共骨架实现,这个不看了,简单看下BlockingQueue接口:
public interface BlockingQueue<E> extends Queue<E> {
/**
* 将一个元素放入队列。
* 成功返回true;失败抛IllegalStateException异常。
*/
boolean add(E e);
/**
* 将一个元素放入队列。
* 成功返回true;失败返回false。
*/
boolean offer(E e);
/**
* 将一个元素放入队列。
* 如果元素无法放入队列,当前操作线程会等待,直到元素可以放入队列。
*/
void put(E e) throws InterruptedException;
/**
* 将一个元素放入队列。
* 如果元素无法放入队列,当前操作线程会等待,直到元素可以放入队列或者
* 给定的时间超时。
* 成功返回true;超时返回false;
*/
boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException;
/**
* 从队列头部获取并删除一个元素。
* 如果无法获取元素,当前操作线程等待,直到有元素可以被获取。
*/
E take() throws InterruptedException;
/**
* 从队列头部获取并删除一个元素。
* 如果无法获取元素,当前操作线程等待,直到有元素可以被获取或者给定时间超时。
* 如果超时,返回null。
*/
E poll(long timeout, TimeUnit unit)
throws InterruptedException;
/**
* 获取队列剩余容量。
*/
int remainingCapacity();
/**
* 移除队列中和给定元素相同的元素。
*/
boolean remove(Object o);
/**
* 判断队列中是否包含给定元素。
*/
public boolean contains(Object o);
/**
* 移除队列中所有的可用元素,并把它们添加到给定集合。
*/
int drainTo(Collection<? super E> c);
/**
* 移除队列中不超过给定数量的可用元素,并把它们添加到给定集合。
*/
int drainTo(Collection<? super E> c, int maxElements);
}
       可以重点关注下put和take方法的行为。
  • 接下来看下ArrayBlockingQueue内部的数据结构:
       ArrayBlockingQueue内部结构非常简单,就是一个数组,一把锁,两个条件;也可以看到,上面提到的公平和非公平策略是由内部的重入锁来支持的。
  • 继续看下ArrayBlockingQueue的重要方法,重点看下put和take,先看下put方法:
    public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
final E[] items = this.items;
final ReentrantLock lock = this.lock;
//由于需要支持方法可中断行为,这里使用可中断的锁操作。
lock.lockInterruptibly();
try {
try {
while (count == items.length)
notFull.await();//队列满时,在notFull条件上等待。
} catch (InterruptedException ie) {
notFull.signal(); // 被中断后,唤醒其他等待notFull条件的线程。
throw ie;
}
insert(e);
} finally {
lock.unlock();
}
} /**
* Circularly increment i.
*/
final int inc(int i) {
return (++i == items.length)? 0 : i;
}
/**
* 在内部数组的putIndex位置插入元素,调整putIndex和count,然后唤醒notEmpty条件上等待的线程。
* 本方法只有在持有锁的情况下才会被调用。
*/
private void insert(E x) {
items[putIndex] = x;
putIndex = inc(putIndex);
++count;
notEmpty.signal();
}

再看下take方法:

    public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
try {
while (count == 0)
notEmpty.await();//队列空时,在notEmpty条件上等待。
} catch (InterruptedException ie) {
notEmpty.signal(); // 被中断后,唤醒其他等待notEmpty条件的线程。
throw ie;
}
E x = extract();
return x;
} finally {
lock.unlock();
}
}
/**
* 从takeInde的位置取出元素,增加takeIndex,减少count,唤醒在notFull上等待的线程。
* 本方法只有在持有锁的情况下才会被调用。
*/
private E extract() {
final E[] items = this.items;
E x = items[takeIndex];
items[takeIndex] = null;
takeIndex = inc(takeIndex);
--count;
notFull.signal();
return x;
}
  • 其他方法的实现也都比较简单,不进行一一解析。最后注意一下,ArrayBlockingQueue的Iterator是弱一致的。

Jdk1.6 JUC源码解析(12)-ArrayBlockingQueue的更多相关文章

  1. Jdk1.6 JUC源码解析(13)-LinkedBlockingQueue

    功能简介: LinkedBlockingQueue是一种基于单向链表实现的有界的(可选的,不指定默认int最大值)阻塞队列.队列中的元素遵循先入先出 (FIFO)的规则.新元素插入到队列的尾部,从队列 ...

  2. Jdk1.6 JUC源码解析(6)-locks-AbstractQueuedSynchronizer

    功能简介: AbstractQueuedSynchronizer(以下简称AQS)是Java并发包提供的一个同步基础机制,是并发包中实现Lock和其他同步机制(如:Semaphore.CountDow ...

  3. Jdk1.6 JUC源码解析(7)-locks-ReentrantLock

    功能简介: Java代码层面提供的锁机制,可做为Synchronized(jvm内置)的替代物,和Synchronized一样都是可重入的. 与Synchronized相比较而言,ReentrantL ...

  4. Jdk1.6 JUC源码解析(1)-atomic-AtomicXXX

    转自:http://brokendreams.iteye.com/blog/2250109 功能简介: 原子量和普通变量相比,主要体现在读写的线程安全上.对原子量的是原子的(比如多线程下的共享变量i+ ...

  5. 【JUC源码解析】ScheduledThreadPoolExecutor

    简介 它是一个线程池执行器(ThreadPoolExecutor),在给定的延迟(delay)后执行.在多线程或者对灵活性有要求的环境下,要优于java.util.Timer. 提交的任务在执行之前支 ...

  6. 【JUC源码解析】Exchanger

    简介 Exchanger,并发工具类,用于线程间的数据交换. 使用 两个线程,两个缓冲区,一个线程往一个缓冲区里面填数据,另一个线程从另一个缓冲区里面取数据.当填数据的线程将缓冲区填满时,或者取数据的 ...

  7. 【JUC源码解析】SynchronousQueue

    简介 SynchronousQueue是一种特殊的阻塞队列,该队列没有容量. [存数据线程]到达队列后,若发现没有[取数据线程]在此等待,则[存数据线程]便入队等待,直到有[取数据线程]来取数据,并释 ...

  8. 【JUC源码解析】ForkJoinPool

    简介 ForkJoin 框架,另一种风格的线程池(相比于ThreadPoolExecutor),采用分治算法,工作密取策略,极大地提高了并行性.对于那种大任务分割小任务的场景(分治)尤其有用. 框架图 ...

  9. 【JUC源码解析】DelayQueue

    简介 基于优先级队列,以过期时间作为排序的基准,剩余时间最少的元素排在队首.只有过期的元素才能出队,在此之前,线程等待. 源码解析 属性 private final transient Reentra ...

随机推荐

  1. For循环及例题

    For循环    (1)循环操作某一个功能(执行某段代码)    (2)四要素                  循环初始值                  循环条件                 ...

  2. Jmeter-添加检查点

    JMeter里面的检查点通过添加断言来完成. 检查用户名和密码参数化的文件user.dat有没有正确调用,添加断言,可以在结果树中查看结果. 1.添加响应断言,右键点击HTTP请求"ts1后 ...

  3. python 爬取w3shcool的JQuery的课程并且保存到本地

    最近在忙于找工作,闲暇之余,也找点爬虫项目练练手,写写代码,知道自己是个菜鸟,但是要多加练习,书山有路勤为径.各位爷有测试坑可以给我介绍个啊,自动化,功能,接口都可以做. 首先呢,我们明确需求,很多同 ...

  4. iOS StoreKit

    简述: 本文讲解iOS系统框架StoreKit中的SKStoreProductViewController与SKStoreReviewController这两个Controller. SKStoreP ...

  5. Maven项目热部署到Tomcat容器下

    第一步: 配置Tomcat的登陆的用户名与密码     在 apache-tomcat-7.0.33\conf\ tomcat-users.xml,第40行添加如下: <role rolenam ...

  6. 移植 DeepinQQ 到 Fedora 中

    本着自由/开源软件的分享精神创作此文,如有任何权力侵害请联系我,我将积极配合. 移植 DeepinQQ 到 Fedora 中 --也不知道是用移植还是迁移更合适 写在前面 首先,在这里要感谢武汉深之度 ...

  7. VS窗体选择BackGroupImage属性报错:已添加具有相同键的项

    高墙我今天第一次遇见这个问题.既然说是"已添加具有相同键的项."那我自然地认为会不会是文件夹哪里命名了两个相同的文件名.然后在这个Exception上越走越远. 好了不说废话.出现 ...

  8. Jackson序列化实例

    参考文章 Jackson使用ContextualSerializer在序列化时获取字段注解的属性 使用BeanSerializerModifier定制jackson的自定义序列化(null值的处理) ...

  9. windows下用cordova构建android app

    最近用到cordova打包apk,总结了下,写下来给大家分享. 一.前期准备工作: 1.安装node   6.2.0 *64 下载地址:链接:http://pan.baidu.com/s/1eS7Ts ...

  10. 每天一个linux命令(62):sh命令 /Linux中执行shell脚本的4种方法总结

    bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限. 方法一:切换到shell脚本所在 ...