【源码】JUC —— BlockingDeque LinkedBlockingDeque 浅析

前言

public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E>

BlockingDeque 拓展了 BlockingQueueDeque,即它是可以是一个 队列、一个 双端队列,同时也支持插入和取出时的 可阻塞 操作

关于 Queue BlockingQueue 相关,可以阅读下面文章

【源码】Queue AbstractQueue PriorityQueue 浅析

【源码】JUC —— BlockingQueue ArrayBlockingQueue 浅析

BlockingDeque

BlockingDeque 的方法整理如下

头部操作失败时抛异常返回特定值阻塞操作定时阻塞操作
插入addFirst(e)offerFirst(e)putFirst(e)offerFirst(e, time, unit)
取出removeFirst()pollFirst()takeFirst()pollFirst(time, unit)
检索getFirst()peekFirst()————
尾部操作失败时抛异常返回特定值阻塞操作定时阻塞操作
插入addLast(e)offerLast(e)putLast(e)offerLast(e, time, unit)
取出removeLast()pollLast()takeLast()pollLast(time, unit)
检索getLast()peekLast()————

同时,BlockingDeque 继承了 BlockingQueue,因为也可以当做一个 FIFO 的单向队列使用,对应的方法映射如下

对比BlockingQueueBlockingDeque
插入add(e)addLast(e)
offer(e)offerLast(e)
put(e)putLast(e)
offer(e, time, unit)offerLast(e, time, unit)
取出remove()removeFirst()
poll()pollFirst()
take()takeFirst()
poll(time, unit)pollFirst(time, unit)
检索element()getFirst()
peek()peekFirst()

LinkedBlockingDeque

基于 链表 实现的 BlockingDeque

Node

static final class Node<E> {

        // 元素
        E item;

        // 前置
        Node<E> prev;

        // 后置
        Node<E> next;

        Node(E x) {
            item = x;
        }
    }

链表的节点以内部类 Node 维护,属性包括 元素前置节点后置节点

属性、构造方法

	// 头节点
    transient Node<E> first;

    // 尾节点
    transient Node<E> last;

    // 元素个数
    private transient int count;

    // 容量
    private final int capacity;

    // 锁对象
    final ReentrantLock lock = new ReentrantLock();

    // take 操作的阻塞队列
    private final Condition notEmpty = lock.newCondition();

    // put 操作的阻塞队列
    private final Condition notFull = lock.newCondition();

	----------------- 构造方法 ----------------------
	
	// 默认容量 Integer.MAX_VALUE
    public LinkedBlockingDeque() {
        this(Integer.MAX_VALUE);
    }

    // 自定义容量
    public LinkedBlockingDeque(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
    }

	// 以指定集合初始化
    public LinkedBlockingDeque(Collection<? extends E> c) {
        this(Integer.MAX_VALUE);
        addAll(c);
    }

不同于 ArrayBlockingQueue 的是,可以不指定 容量,默认为 Integer.MAX_VALUE

头插入操作

	public void addFirst(E e) {
		// 插入失败抛出异常
        if (!offerFirst(e))
            throw new IllegalStateException("Deque full");
    }

	public boolean offerFirst(E e) {
        if (e == null) throw new NullPointerException();
        Node<E> node = new Node<E>(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return linkFirst(node);
        } finally {
            lock.unlock();
        }
    }

	public void putFirst(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();
        Node<E> node = new Node<E>(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            // 如果插入失败(队列满了)则阻塞直到插入成功
            while (!linkFirst(node))
                notFull.await();
        } finally {
            lock.unlock();
        }
    }

	public boolean offerFirst(E e, long timeout, TimeUnit unit)
        throws InterruptedException {
        if (e == null) throw new NullPointerException();
        Node<E> node = new Node<E>(e);
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            // 如果插入失败(队列满了)则阻塞指定时间(nanos)
            while (!linkFirst(node)) {
                if (nanos <= 0L)
                    return false;
                nanos = notFull.awaitNanos(nanos);
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

	private boolean linkFirst(Node<E> node) {
        /**
         * 必须持有锁
         * 容量已满插入失败,返回 false
         *
         * f 指向 first
         * node 的 next 指向 first
         * first 指向 node
         * 如果 last == null,即首次插入
         * 则 last 也指向 node
         * 否则 f 的 prev 指向 node
         *
         * 元素个数累加
         * notEmpty 唤醒一个 take 线程
         */
        if (count >= capacity)
            return false;
        Node<E> f = first;
        node.next = f;
        first = node;
        if (last == null)
            last = node;
        else
            f.prev = node;
        ++count;
        notEmpty.signal();
        return true;
    }

最终由 linkFirst 实现节点插入,具体的细节可见注释

尾插入操作

头插入操作 同理,略

头获取操作

	public E removeFirst() {
        E x = pollFirst();
        // 获取失败(队列为空),则抛出异常
        if (x == null) throw new NoSuchElementException();
        return x;
    }

	public E pollFirst() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return unlinkFirst();
        } finally {
            lock.unlock();
        }
    }

	public E takeFirst() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E x;
            // 若队列为空,则阻塞直到取到元素
            while ( (x = unlinkFirst()) == null)
                notEmpty.await();
            return x;
        } finally {
            lock.unlock();
        }
    }

	public E pollFirst(long timeout, TimeUnit unit)
        throws InterruptedException {
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            E x;
            // 若队列为空,则阻塞指定时间(nanos)
            while ( (x = unlinkFirst()) == null) {
                if (nanos <= 0L)
                    return null;
                nanos = notEmpty.awaitNanos(nanos);
            }
            return x;
        } finally {
            lock.unlock();
        }
    }

	private E unlinkFirst() {
        /**
         * 必须持有锁
         *
         * f 指向 node
         * f == null,即队列为空,返回 null
         * n 指向 f 的 next
         * item 指向 f 的 item
         * f 的 item 置为 null
         * f 的 next 指向 f,此时 f 可以被 GC 回收了
         *
         * first 指向 n
         * 如果 n == null,则队列为空了,last 也指向 null
         * 否则 n 的 prev 指向 null
         * 元素个数递减
         * 唤醒一个 put 操作线程
         */
        Node<E> f = first;
        if (f == null)
            return null;
        Node<E> n = f.next;
        E item = f.item;
        f.item = null;
        f.next = f; // help GC
        first = n;
        if (n == null)
            last = null;
        else
            n.prev = null;
        --count;
        notFull.signal();
        return item;
    }

最终由 unlinkFirst 实现节点获取,具体的细节可见注释

尾获取操作

头获取操作 同理,略

检索操作

	public E getFirst() {
        E x = peekFirst();
        
        // 没有元素则抛出异常
        if (x == null) throw new NoSuchElementException();
        return x;
    }

	public E peekFirst() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            // 返回 first 的 item
            return (first == null) ? null : first.item;
        } finally {
            lock.unlock();
        }
    }

头检索 即返回 first.item,同理 尾检索 返回 last.item

BlockingQueue 方法委托

上文提到 BlockingDeque 也是一个 BlockingQueue,也给出了方法的对应关系,那么实现就是简单的方法委托

	public boolean add(E e) {
        addLast(e);
        return true;
    }

    public boolean offer(E e) {
        return offerLast(e);
    }

    public void put(E e) throws InterruptedException {
        putLast(e);
    }

    public boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException {
        return offerLast(e, timeout, unit);
    }

    public E remove() {
        return removeFirst();
    }

    public E poll() {
        return pollFirst();
    }

    public E take() throws InterruptedException {
        return takeFirst();
    }

    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        return pollFirst(timeout, unit);
    }

    public E element() {
        return getFirst();
    }

    public E peek() {
        return peekFirst();
    }

Stack 方法委托

同理,BlockingDeque 也可以是个 Stack(栈)

	public void push(E e) {
        addFirst(e);
    }

    public E pop() {
        return removeFirst();
    }

其他方法

LinkedBlockingDeque 还实现了诸如 remove(Object o) size() contains(Object o) addAll(Collection<? extends E> c) 等很多方法,不再一一解读了

总结

本文介绍了 BlockingDeque 接口和基于链表实现的 LinkedBlockingDeque ,同时支持 队列双端队列可阻塞 操作,十分强大

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值