阻塞队列

阻塞队列有几个实现:

  • ArrayBlockingQueue
  • LinkedBlockingQueue
  • PriorityBlockingQueue
  • DelayQueue
  • SynchronousQueue
  • LinkedTransferQueue
  • LinkedBlockingDeque

他们的共同父类是AbstractQueue。我们一起看ArrayBlockingQueue的实现。

ArrayBlockingQueue,数组、有界、出入队阻塞

数据存储

数据存储在数组中,用几个变量标记下一个获取或存储的元素:

    /** The queued items */
final Object[] items; // 用数组存储元素 /** items index for next take, poll, peek or remove */
int takeIndex; // 返回元素的下标 /** items index for next put, offer, or add */
int putIndex; // 插入元素的下标 /** Number of elements in the queue */
int count; // 数量

阻塞逻辑

添加、删除元素需要使用ReentrantLock加锁,满队列、空队列情况的等待与唤醒使用各自的Condition:

    public ArrayBlockingQueue(int capacity, boolean fair) {
...
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}

插入元素,返回是否成功

    public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length) // 队列满,插入不成,返回false
return false;
else {
enqueue(e);
return true; // 插入成功,返回true
}
} finally {
lock.unlock();
}
}

插入元素,成功返回true,失败抛出异常

它调用offer方法,插入成功返回true,失败抛出异常:

    public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}

插入元素,队列满了则阻塞

    public void put(E e) throws InterruptedException {
checkNotNull(e); // e为空抛出异常
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) // 当队列满了
notFull.await(); // notFull的Condition等待条件成熟
enqueue(e); // 条件成熟了才插入元素
} finally {
lock.unlock();
}
}

插入元素,队列满了则阻塞指定超时时间

主体逻辑与put(E e)一致,只是加了超时逻辑:

    public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException { checkNotNull(e);
long nanos = unit.toNanos(timeout); // 将超时时间转换为Nano单位
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) {
if (nanos <= 0) // 超时了,返回false
return false;
nanos = notFull.awaitNanos(nanos); // Condition等待指定时间
}
enqueue(e);
return true; // 超时时间内插入成功,返回true
} finally {
lock.unlock();
}
}

删除元素,返回是否删除成功

    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])) { // 遍历到要删除的元素,删除并返回true
removeAt(i);
return true;
}
if (++i == items.length)
i = 0;
} while (i != putIndex);
}
return false; // 遍历完毕,没有找到,返回false
} finally {
lock.unlock();
}
}

删除元素,返回删除的元素,没匹配到返回null

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

删除元素,队列为空则阻塞

    public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0) // 队列为空
notEmpty.await(); // 元素出队,队列元素为空,等待非空条件成熟
return dequeue();
} finally {
lock.unlock();
}
}

入队逻辑,入队成功后同时非空条件成熟:

    private void enqueue(E x) { // 入队
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0;
count++;
notEmpty.signal(); // 元素入队后,通知非空条件已成熟
}

删除元素,队列为空阻塞指定超时时间

主体逻辑与take()一直,但有等待超时逻辑:

    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout); // 转化为nano单位
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos); // 等待指定超时时间
}
return dequeue();
} finally {
lock.unlock();
}
}

LinkedBlockingQueue,链表、有界、出入队阻塞

存储结构

用链表作为存储,Node是链表的节点:

    static class Node<E> {
E item; // 元素值 /**
* One of:
* - the real successor Node
* - this Node, meaning the successor is head.next
* - null, meaning there is no successor (this is the last node)
*/
Node<E> next; // 下一节点 Node(E x) { item = x; } // 构造方法
}

PriorityBlockingQueue,无界,出队阻塞

出队阻塞

它是无界的,所以只有出队时队列无元素才会堵塞,依赖notEmpty的Condition:

    /**
* Condition for blocking when empty
*/
private final Condition notEmpty;

优先级顺序

它的优先级依赖比较器:

    /**
* The comparator, or null if priority queue uses elements'
* natural ordering.
*/
private transient Comparator<? super E> comparator;

DelayQueue,无界、出队阻塞、等待指定时间才能出队

数据存储

它的数据实现依赖于PriorityQueue,所以队列的元素需实现Comparable:

    private final PriorityQueue<E> q = new PriorityQueue<E>();

出队

    public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
E first = q.peek(); // 获取下一个即将的出队元素
if (first == null || first.getDelay(NANOSECONDS) > 0) // 如果无出队元素,或出队元素的时间未到
return null;
else
return q.poll(); // 实际的出队
} finally {
lock.unlock();
}
}

阻塞出队

    public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
E first = q.peek(); // 获取将要出队的元素
if (first == null) // 为空,则等待
available.await();
else {
long delay = first.getDelay(NANOSECONDS);
if (delay <= 0) // 时间已到,出队,跳出方法
return q.poll();
first = null; // don't retain ref while waiting // 等待期间取消引用
if (leader != null) # TODO,未理解透彻
available.await();
else {
Thread thisThread = Thread.currentThread();
leader = thisThread; // 当前线程赋予leader
try {
available.awaitNanos(delay); // 等待剩余时间
} finally {
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
if (leader == null && q.peek() != null)
available.signal();
lock.unlock();
}
}

SynchronousQueue,阻塞队列,不存储元素

依赖于TransferQueue和TransferStack

它可设置是否公平,分别依赖于TransferQueue和TransferStack,默认非公平

    public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}

阻塞入队和出队

    public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
if (transferer.transfer(e, false, 0) == null) {
Thread.interrupted();
throw new InterruptedException();
}
}
    public E take() throws InterruptedException {
E e = transferer.transfer(null, false, 0);
if (e != null)
return e;
Thread.interrupted();
throw new InterruptedException();
}

【Java】Java Queue的简介的更多相关文章

  1. java中Queue简介

    Queue: 基本上,一个队列就是一个先入先出(FIFO)的数据结构 offer,add区别:一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝.这时新的 offer 方法 ...

  2. Lucene:基于Java的全文检索引擎简介

    Lucene:基于Java的全文检索引擎简介 Lucene是一个基于Java的全文索引工具包. 基于Java的全文索引/检索引擎--Lucene Lucene不是一个完整的全文索引应用,而是是一个用J ...

  3. Java中的队列:java.util.Queue接口

    队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作. Queue接口与List.Set同一级别,都是继承了Collection接口.Linked ...

  4. java中使用队列:java.util.Queue

    在java5中新添加了java.util.Queue接口,用以支持队列的常见操作.该接口扩展了java.util.Collection接口.Queue使用时要尽量避免Collection的add()和 ...

  5. java集合--Queue用法

    队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作.进行插入操作的端称为队尾,进行删除操作的端称为队头.队列中没有元素时,称为空队列. 在队列这 ...

  6. Jconsole: JAVA 监视和管理控制台简介

    Jconsole: JAVA 监视和管理控制台简介 JDK中除了提供大量的命令行之外,还提供两个功能强大的可视化工具:JConsole和VisualVM. 之前对java的调试一直停留在 右键-> ...

  7. java.util.Queue用法

    队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作.进行插入操作的端称为队尾,进行删除操作的端称为队头.队列中没有元素时,称为空队列. 在队列这 ...

  8. java队列——queue详细分析

    Queue: 基本上,一个队列就是一个先入先出(FIFO)的数据结构 Queue接口与List.Set同一级别,都是继承了Collection接口.LinkedList实现了Deque接 口.   Q ...

  9. java assert的用法简介【转】

    assert的基本用法 assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制,如C,C++和Eiffel等,但是支持的形式不尽相同,有的是通过语言本身.有的是通过库 ...

  10. Java的MVC模式简介

    Java的MVC模式简介 MVC(Model View Control)模型-视图-控制器 首先我们需要知道MVC模式并不是javaweb项目中独有的,MVC是一种软件工程中的一种软件架构模式,把软件 ...

随机推荐

  1. 今天刚学到truncate和delete的区别,做个总结吧

    truncate table : 删除内容,释放空间(表中数据会被删除,但不会进入oracle回收站,直接删除),不删除定义 delete table : 删除内容,不释放空间(表中数据虽被删除,但是 ...

  2. 《Android进阶之光》--RxJava结合Retrofit访问网络

    1)配置 dependencies{ ... compile 'io.reactivex:rxjava:1.2.0' compile 'io.reactivex:rxandroid:1.2.1' co ...

  3. Linux学习之常用文件处理命令(一)

    (一)文件命名规则 (二)常用文件处理命令 1.ls命令 2.cd命令 3.pwd命令 4.mkdir命令 5.touch命令 6.cp命令 7.mv命令 8.rm命令 9.cat命令 10.more ...

  4. RabbitMQ 初学及其深入学习推荐的一些文章

    记录一下学习RabbitMQ过程中,收获比较大的一些文章: 什么都别说,先把这6个Demo 玩一遍 https://www.rabbitmq.com/getstarted.html 大佬1号 http ...

  5. <<c专家编程>>笔记

    C专家编程摘录 c操作符的优先级 有时一些c操作符有时并不会像你想象的那样工作. 下方表格将说明这个问题: 优先级问题 表达式 期望的情况 实际情况 . 优先级高于* *p.f (*p).f *(p. ...

  6. 洛谷P2105 K皇后

    To 洛谷.2105 K皇后 题目描述 小Z最近捡到了一个棋盘,他想在棋盘上摆放K个皇后.他想知道在他摆完这K个皇后之后,棋盘上还有多少了格子是不会被攻击到的. (Ps:一个皇后会攻击到这个皇后所在的 ...

  7. Unity 4.0 中的新动画系统——MecAnim

    分享一个文档资料,关于动画系统的,版本应该很老了,但是有借鉴意义的: Unity 4.0 已于 2012 年 11 月 15 日正式发布,Unity 每一次版本的提升,都给游戏开发者带来惊喜,这一次也 ...

  8. Oracle 增加 修改 删除 列

    语法结构如下: alter table tablename add (column datatype [default value][null/not null],….); alter table t ...

  9. 基于Material-Design的Gank-IO客户端

    title: 基于Material Design的Gank IO客户端 date: 2017-03-13 12:58:03 tags: - Android - Material Design - Rx ...

  10. shutdown vs close

    shutdown 和 close关闭tcp连接的介绍网上有很多,主要区别如下: 1.调用close后,将中止通信.删除套接字.丢弃数据.但是,注意喽,但是,如果有多个进程共享一个套接字,close每被 ...