OpenJDK8 Queue和Deque

本文详细介绍了OpenJDK8中的Queue和Deque,包括Queue接口、AbstractQueue、BlockingQueue及其具体实现如ArrayBlockingQueue、LinkedBlockingQueue、DelayQueue和PriorityQueue。此外,还探讨了Deque接口、BlockingDeque接口以及ArrayDeque的数据结构、线程安全性和源码分析。
摘要由CSDN通过智能技术生成

1. 整体类图

在这里插入图片描述

从图上可以看到,内容主要可以分成2个部分,分别为Queue队列、Deque双端队列,其中Deque还提供了Stack栈的功能。

2. Queue相关

2.1 Queue接口

提供了队列的通用操作方法声明。可以看做一个排队队伍,新来的人要排在队尾(新增/offer),按次序叫号,最先叫的都是队首(获取/poll)。

/**
 * 队列接口
 * 提供了两套操作队列方法:
 * 1)抛异常, add/remove/element
 * 2) 返回false/null,offer/poll/peek
 * 并不强求实现类满足(FIFO先进先出)顺序要求。比如Stack(LIFO后进先出)、优先队列
 * @since 1.5
 */
public interface Queue<E> extends Collection<E> {
   
    /**
     * 队尾插入元素
     * 如果空间达到上限,抛异常IllegalStateException
     */
    boolean add(E e);
    /**
     * 从队首获取并删除元素
     * 如果队列为空,抛NoSuchElementException 异常,
     */
    E remove();
    /**
     * 获取队首元素,并不移除
     * 如果队列为空,抛NoSuchElementException异常
     */
    E element();

    /**
     * 队尾插入元素
     */
    boolean offer(E e);
    /**
     * 从对手获取并删除元素
     * 如果队列为空,返回null
     */
    E poll();

    /**
     * 获取对手元素,并不删除
     * 如果队列为空,返回null
     */
    E peek();
}

2.2 AbstractQueue抽象类

基于Queue接口方法做了一定的内部封装

/**
 * 提供了部分队列操作的实现。
 * 添加(offer)、删除(poll)、获取元素(peek)操作
 * 失败抛异常,而不是返回false/null
 * 不允许null值
 * @since 1.5
 */
public abstract class AbstractQueue<E>
    extends AbstractCollection<E>
    implements Queue<E> {
   

    /**
     * 子类调用的默认构造
     */
    protected AbstractQueue() 

    /**
     * 往队列中添加元素
     * 添加成功,返回true
     * 如果容量达到上限,抛异常 IllegalStateException
     */
    public boolean add(E e) 

    /**
     * 移除队列头元素并返回
     * NoSuchElementException 无元素异常
     */
    public E remove()

    /**
     * 提取队列头元素,不删除。
     * 区别于peek方法,当队列空时,抛NoSuchElementException无元素异常
     */
    public E element() 

    /**
     * 清空队列中所有元素
     * 通过poll方法实现
     */
    public void clear() {
   
        while (poll() != null)
            ;
    }

    /**
     * 从集合c中添加所有元素进队列。
     * 如果添加的是队列本身,抛异常IllegalStateException
     * 添加的元素顺序遵从集合迭代器迭代顺序
     */
    public boolean addAll(Collection<? extends E> c)
}

2.3 BlockingQueue阻塞队列接口

其内部方法主要分为四种返回

1)抛异常
2) 返回值
3) 操作无期限阻塞,直到满足条件
4) 操作在给定时间内有限阻塞

方法主要分为如下三种类型:

非阻塞方法:add、offer、remove、poll
无限期阻塞:put、take
有限时间阻塞:offer(时间)、poll(时间)
/**
 * 阻塞队列接口
 * 获取元素时如果队列为空。操作阻塞直到有元素插入队列
 * 插入元素时如果空间上限。插入阻塞直到空间腾出来
 * 不允许null值,会抛NullPointerException
 * 
 * 线程安全
 * @since 1.5
 */
public interface BlockingQueue<E> extends Queue<E> {
   
    /**
     * 往队尾添加元素 (非阻塞)
     * 如果容量上限,抛异常IllegalStateException
     */
    boolean add(E e);

    /**
     * 往队尾添加元素 (非阻塞)
     * 如果容量上限,抛异常IllegalStateException
     */
    boolean offer(E e);

    /**
     * 往队尾添加元素 (无期限阻塞)
     * 如果容量上限,阻塞直到有空余容量
     * 如果线程中断,抛异常InterruptedException
     */
    void put(E e) throws InterruptedException;

    /**
     * 往队尾添加元素 (有限时间阻塞)
     * 如果达到最大时间,线程中断,抛异常InterruptedException
     */
    boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException;

    /**
     * 从队首获取并删除元素 (无期限阻塞)
     * 如果队列为空,阻塞直到有元素
     * 如果线程中断,抛异常InterruptedException
     */
    E take() throws InterruptedException;

    /**
     * 从队首获取并删除元素 (有限时间阻塞)
     * 如果达到最大时间,线程中断,抛异常InterruptedException
     */
    E poll(long timeout, TimeUnit unit)
        throws InterruptedException;

    /**
     * 队列剩余容量
     */
    int remainingCapacity();

    /**
     * 从队列元素中移除单个特定元素(非阻塞)
     * 如果不存在,抛异常NullPointerException
     */
    boolean remove(Object o);

    /**
     * 判断队列中是否存在特定元素
     * 如果没有,抛异常NullPointerException
     */
    public boolean contains(Object o);

    /**
     * 移除队列中所有元素,并将元素放到给定集合c中
     */
    int drainTo(Collection<? super E> c);

    /**
     * 移除队列中所有元素,并将元素放到给定集合c中.最多只迁移maxElements个元素
     */
    int drainTo(Collection<? super E> c, int maxElements);
}

2.4 ArrayBlockingQueue基于数组的阻塞队列

2.4.1 数据结构

固定容量循环数组

2.4.2 线程安全

ArrayBlockingQueue类内有三个主要用于线程同步的变量

// 可重入锁,并发环境下主要的加锁方案
final ReentrantLock lock;
// 阻塞取的标志条件
private final Condition notEmpty;
// 阻塞插的标志条件
private final Condition notFull;

2.4.3 源码

/**
 * 基于数组实现的有界阻塞队列
 * 元素顺序FIFO先进先出。队尾插数据,队首取数据
 * 初始化后 容量不可变
 * @since 1.5
 */
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
   

    // 队列元素底层数组存储(循环数组)
    final Object[] items;
    // 队首索引
    int takeIndex;
    // 队尾索引
    int putIndex;
    // 队列元素量
    int count;

    // 可重入锁,并发环境下主要的加锁方案
    final ReentrantLock lock;
    // 阻塞取的标志条件
    private final Condition notEmpty;
    // 阻塞插的标志条件
    private final Condition notFull;

    transient Itrs itrs = null;
    
    /**
     * 辅助方法 - 循环获取索引
     */
    final int dec(int i)
    /**
     * 辅助方法 - 返回索引i上的元素
     */
    final E itemAt(int i)
    /**
     * 辅助方法 - 判断元素是否为空
     */
    private static void checkNotNull(Object v)

    /**
     * 插入元素
     */
    private void enqueue(E x) {
   
        final Object[] items = this.items;
        items[putIndex] = x;
        // 如果已经到数组尾,循环设置尾部到索引位置0
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        // 阻塞取的释放信号
        notEmpty.signal();
    }

    /**
     * 提取并删除元素
     */
    private E dequeue() {
   
        final Object[] items = this.items;
        E x = (E) items[takeIndex];
        items[takeIndex] = null;
        // 如果已经到数组尾,循环设置尾部到索引位置0
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        // 阻塞插的释放信号
        notFull.signal();
        return x;
    }

    /**
     * 删除指定索引位的元素
     */
    void removeAt(final int removeIndex) {
   
        final Object[] items = this.items;
        // 移除元素刚好在队列头
        if (removeIndex == takeIndex) {
   
            items[takeIndex] = null;
            if (++takeIndex == items.length)
                takeIndex = 0;
            count--;
            // 迭代器起始移到下一个
            if (itrs != null)
                itrs.elementDequeued();
        } else {
   
            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();
    }

    /**
     * 构造指定容量,默认策略(公平锁、非抢占式)的ArrayBlockingQueue
     */
    public ArrayBlockingQueue(int capacity) {
   
        this(capacity, false);
    }

    /**
     * 构造指定容量,指定策略的ArrayBlockingQueue
     */
    public ArrayBlockingQueue(int capacity, boolean fair)
    /**
     * 从给定集合c中,构造指定容量,指定策略的ArrayBlockingQueue
     */
    public ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c)
                              
    /**
     * 队尾添加元素
     * 如果容量上限,抛异常IllegalStateException
     */
    public boolean add(E e) 
    /**
     * 队尾插入元素
     * 如果容量上限,返回false
     */
    public boolean offer(E e) 
    /**
     * 队尾插入元素(无限阻塞)
     */
    public void put(E e) throws InterruptedException 
    /**
     * 队尾插入元素(有限时间阻塞)
     */
    public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException 
    public E poll() 
    public E take() throws InterruptedException
    public E poll(long timeout, TimeUnit unit) throws InterruptedException
    public E peek() 

    /**
     * 返回队列的元素数量
     */
    public int size() 

    /**
     * 返回队列中剩余的容量
     */
    public int remainingCapacity()

    /**
     * 移除队列中首次出现的元素
     */
    public boolean remove(Object o)

    /**
     * 判断队列中是否包含指定元素
     */
    public boolean contains(Object o) 

    /**
     * 将队列元素转成数组
     */
    public Object[] toArray()
    /**
     * 将队列元素转成数组,
     * 如果容量大于给定数组元素,新建数组
     */
    public <T> T[] toArray(T[] a) 
    public String toString() 
    public void clear() 

    /**
     * 将队列中元素迁移至集合c
     */
    public int drainTo(Collection<? super E> c) 
    /**
     * 将队列中元素迁移至集合c,最多添加maxElements个元素
     */
    public int drainTo(Collection<? super E> c, int maxElements)

    /**
     * 返回迭代器
     */
    public Iterator<E> iterator() 
    /**
     * 返回可分割的迭代器
     * @since 1.8
     */
    public Spliterator<E> spliterator()
}

2.5 LinkedBlockingQueue基于链表的阻塞队列

2.5.1 数据结构

基于单向链表实现

2.5.2 线程安全

采用可重入锁方式实现。

	// 可重入锁:获取元素锁
    private final ReentrantLock takeLock = new ReentrantLock();
    // 队列非空标志。插入元素后触发其释放信号
    private final Condition notEmpty = takeLock.newCondition();
    // 可重入锁:插入元素锁
    private final ReentrantLock putLock = new ReentrantLock();
    // 队列未满标志。获取数据后触发其释放信号
    private final Condition notFull = putLock.newCondition();

2.5.3 源码

/**
 * 基于链表的阻塞队列。
 * 队列顺序满足FIFO先进先出模式
 * @since 1.5
 */
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
   
    /**
     * 链表节点类
     */
    static class Node<E> {
   
        E item;
        Node<E> next;
        Node(E x) {
    item = x; }
    }

    // 容量上限,不指定的话默认就是Integer.MAX_VALUE
    private final int capacity;
    // 原子类记录元素数量
    private final AtomicInteger count = new AtomicInteger();
    // 队列虚头(真实的元素为其head.next)
    transient Node<E> head;
    // 链表尾部
    private transient Node<E> last
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值