zoukankan      html  css  js  c++  java
  • LinkedBlockingDeque 源码分析

    LinkedBlockingDeque

    LinkedBlockingDeque 能解决什么问题?什么时候使用 LinkedBlockingDeque?

    1)LinkedBlockingDeque 是基于双向链表实现的,可以选择有界或无界的双端阻塞队列。
    2)LinkedBlockingDeque 使用相同的互斥锁来保证线程安全性,读写操作性能低于 LinkedBlockingQueue。
    

    如何使用 LinkedBlockingDeque?

    1)并发场景下,需要作为双端队列使用时,如果只是作为 FIFO 队列使用,则 LinkedBlockingQueue 的性能更高。
    2)指定队列的容量,以避免生产速率远高于消费速率时资源耗尽的问题。
    

    使用 LinkedBlockingDeque 有什么风险?

    1)未指定容量的情况下,生产速率远高于消费速率时,会导致内存耗尽而 OOM。
    2)高并发场景下,性能远低于 LinkedBlockingQueue。
    3)由于需要维持前后节点的链接,内存消耗也高于 LinkedBlockingQueue。
    

    LinkedBlockingDeque 核心操作的实现原理?

    • 创建实例
        /** 双向链表节点 */
        static final class Node<E> {
            /**
             *  节点元素,如果节点已经被移除,则为 null
             */
            E item;
    
            /**
             * One of:
             * - the real predecessor Node
             * - this Node, meaning the predecessor is tail
             * - null, meaning there is no predecessor
             */
            Node<E> prev;
    
            /**
             * One of:
             * - the real successor Node
             * - this Node, meaning the successor is head
             * - null, meaning there is no successor
             */
            Node<E> next;
    
            Node(E x) {
                item = x;
            }
        }
    
        /**
         *  头结点
         * Invariant: (first == null && last == null) ||
         *            (first.prev == null && first.item != null)
         */
        transient Node<E> first;
    
        /**
         *  尾节点
         * Invariant: (first == null && last == null) ||
         *            (last.next == null && last.item != null)
         */
        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);
        }
    
        /**
         *  创建一个容量为 capacity 的双端阻塞队列
         */
        public LinkedBlockingDeque(int capacity) {
            if (capacity <= 0) {
                throw new IllegalArgumentException();
            }
            this.capacity = capacity;
        }
    
    • 将目标元素 e 添加到队列头部,如果队列已满,则阻塞等待有可用空间后重试
        /**
         *  将目标元素 e 添加到队列头部,如果队列已满,则阻塞等待有可用空间后重试
         */
        public void putFirst(E e) throws InterruptedException {
            if (e == null) {
                throw new NullPointerException();
            }
            final Node<E> node = new Node<>(e);
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                // 尝试在头部添加元素
                while (!linkFirst(node)) {
                    // 当前线程在非满条件上等待
                    notFull.await();
                }
            } finally {
                lock.unlock();
            }
        }
    
        private boolean linkFirst(Node<E> node) {
            // 队列已满,则直接返回 false
            if (count >= capacity) {
                return false;
            }
            // 读取头节点
            final Node<E> f = first;
            // 将旧头结点链接到目标节点之后
            node.next = f;
            // 写入新头节点
            first = node;
            // 1)当前元素为第一个添加到队列中的元素
            if (last == null) {
                // 写入尾节点
                last = node;
            } else {
                // 将旧头节点的前置节点设置为新头结点
                f.prev = node;
            }
            // 递增计数
            ++count;
            // 唤醒在非空条件上阻塞等待的线程来读取元素
            notEmpty.signal();
            return true;
        }
    
    • 如果队列已满,则直接返回 false,否则将目标元素 e 添加到队列头部
        /**
         *  如果队列已满,则直接返回 false,否则将目标元素 e 添加到队列头部
         */
        @Override
        public boolean offerFirst(E e) {
            if (e == null) {
                throw new NullPointerException();
            }
            final Node<E> node = new Node<>(e);
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                return linkFirst(node);
            } finally {
                lock.unlock();
            }
        }
    
    • 在指定的超时时间内尝试将目标元素 e 添加到队列头部,成功则返回 true
        /**
         *  在指定的超时时间内尝试将目标元素 e 添加到队列头部,成功则返回 true
         */
        @Override
        public boolean offerFirst(E e, long timeout, TimeUnit unit)
                throws InterruptedException {
            if (e == null) {
                throw new NullPointerException();
            }
            final Node<E> node = new Node<>(e);
            long nanos = unit.toNanos(timeout);
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                // 头结点添加失败
                while (!linkFirst(node)) {
                    // 已经超时则直接返回
                    if (nanos <= 0L) {
                        return false;
                    }
                    // 当前线程在非满条件上阻塞等待,唤醒后再次尝试添加
                    nanos = notFull.awaitNanos(nanos);
                }
                return true;
            } finally {
                lock.unlock();
            }
        }
    
    • 将目标元素 e 添加到队列尾部,如果队列已满,则阻塞等待有可用空间后重试
        /**
         *  将目标元素 e 添加到队列尾部,如果队列已满,则阻塞等待有可用空间后重试    
         */
        @Override
        public void putLast(E e) throws InterruptedException {
            if (e == null) {
                throw new NullPointerException();
            }
            final Node<E> node = new Node<>(e);
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                // 尝试将节点链接到队列尾部
                while (!linkLast(node)) {
                    // 队列已满,当前线程在非满条件上阻塞等待,被唤醒后再次尝试
                    notFull.await();
                }
            } finally {
                lock.unlock();
            }
        }
    
        private boolean linkLast(Node<E> node) {
            // 队列已满,则直接返回 false
            if (count >= capacity) {
                return false;
            }
            // 读取尾节点
            final Node<E> l = last;
            // 将目标节点链接到尾节点之后
            node.prev = l;
            // 写入尾节点为新增节点
            last = node;
            // 1)当前元素是第一个加入队列的元素
            if (first == null) {
                // 写入头结点
                first = node;
            } else {
                // 将旧尾节点的后置节点更新为新增节点
                l.next = node;
            }
            // 递增总数
            ++count;
            // 唤醒在非空条件上等待的线程
            notEmpty.signal();
            return true;
        }
    
    • 如果队列已满,则直接返回 false,否则将目标元素 e 添加到队列尾部
        /**
         *  如果队列已满,则直接返回 false,否则将目标元素 e 添加到队列尾部
         */
        @Override
        public boolean offerLast(E e) {
            if (e == null) {
                throw new NullPointerException();
            }
            final Node<E> node = new Node<>(e);
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                return linkLast(node);
            } finally {
                lock.unlock();
            }
        }
    
    • 在指定的超时时间内尝试将目标元素 e 添加到队列尾部,成功则返回 true
        /**
         *  在指定的超时时间内尝试将目标元素 e 添加到队列尾部,成功则返回 true
         */
        @Override
        public boolean offerLast(E e, long timeout, TimeUnit unit)
                throws InterruptedException {
            if (e == null) {
                throw new NullPointerException();
            }
            final Node<E> node = new Node<>(e);
            long nanos = unit.toNanos(timeout);
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                // 尝试将目标元素 e 添加到队列尾部
                while (!linkLast(node)) {
                    // 已经超时则直接返回 false
                    if (nanos <= 0L) {
                        return false;
                    }
                    // 当前线程在非满条件上阻塞等待,被唤醒后再次尝试
                    nanos = notFull.awaitNanos(nanos);
                }
                return true;
            } finally {
                lock.unlock();
            }
        }
    
    • 移除并返回头部节点,如果队列为空,则阻塞等待有可用元素之后重试
        /**
         *  移除并返回头部节点,如果队列为空,则阻塞等待有可用元素之后重试
         * created by ZXD at 6 Dec 2018 T 21:00:25
         * @return
         * @throws InterruptedException
         */
        @Override
        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();
            }
        }
    
    • 移除并返回尾部节点,如果队列为空,则阻塞等待有可用元素之后重试
        /**
         *  移除并返回尾部节点,如果队列为空,则阻塞等待有可用元素之后重试
         * created by ZXD at 6 Dec 2018 T 21:02:04
         * @return
         * @throws InterruptedException
         */
        @Override
        public E takeLast() throws InterruptedException {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                E x;
                // 尝试移除并返回尾部节点
                while ( (x = unlinkLast()) == null) {
                    // 队列为空,则阻塞等待有可用元素之后重试
                    notEmpty.await();
                }
                return x;
            } finally {
                lock.unlock();
            }
        }
    
    • 如果队列为空,则立即返回 null,否则移除并返回头部元素
        /**
         *  如果队列为空,则立即返回 null,否则移除并返回头部元素
         * created by ZXD at 6 Dec 2018 T 21:03:40
         * @return
         */
        @Override
        public E pollFirst() {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                return unlinkFirst();
            } finally {
                lock.unlock();
            }
        }
    
    • 如果队列为空,则立即返回 null,否则移除并返回尾部元素
        /**
         *  如果队列为空,则立即返回 null,否则移除并返回尾部元素
         * created by ZXD at 6 Dec 2018 T 21:04:43
         * @return
         */
        @Override
        public E pollLast() {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                return unlinkLast();
            } finally {
                lock.unlock();
            }
        }
    
    • 在指定的超时时间内尝试移除并返回头部元素,如果已经超时,则返回 null
        /**
         *  在指定的超时时间内尝试移除并返回头部元素,如果已经超时,则返回 null
         * created by ZXD at 6 Dec 2018 T 21:05:21
         * @param timeout
         * @param unit
         * @return
         * @throws InterruptedException
         */
        @Override
        public E pollFirst(long timeout, TimeUnit unit)
                throws InterruptedException {
            long nanos = unit.toNanos(timeout);
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                E x;
                // 尝试移除并返回头部元素
                while ( (x = unlinkFirst()) == null) {
                    // 已经超时则返回 null
                    if (nanos <= 0L) {
                        return null;
                    }
                    // 当前线程在非空条件上阻塞等待,被唤醒后进行重试
                    nanos = notEmpty.awaitNanos(nanos);
                }
                // 移除成功则直接返回头部元素
                return x;
            } finally {
                lock.unlock();
            }
        }
    
    • 在指定的超时时间内尝试移除并返回尾部元素,如果已经超时,则返回 null
        /**
         * created by ZXD at 6 Dec 2018 T 21:08:24
         * @param timeout
         * @param unit
         * @return
         * @throws InterruptedException
         */
        @Override
        public E pollLast(long timeout, TimeUnit unit)
                throws InterruptedException {
            long nanos = unit.toNanos(timeout);
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                E x;
                 // 尝试移除并返回尾部元素
                while ( (x = unlinkLast()) == null) {
                    // 已经超时则返回 null
                    if (nanos <= 0L) {
                        return null;
                    }
                    // 当前线程在非空条件上阻塞等待,被唤醒后进行重试
                    nanos = notEmpty.awaitNanos(nanos);
                }
                // 移除成功则直接返回尾部元素
                return x;
            } finally {
                lock.unlock();
            }
        }
    
  • 相关阅读:
    代办事项
    问题总结2015/05/05
    Android Studio 更新
    Android 防内存泄露handler
    android canvas 绘图笔记
    Android Studio compile error : enum constant INSTANT_RUN_REPLACEMENT does not exist in class
    android Studio 配置LUA 开发环境
    Android 性能优化之(1)-MAT使用教程
    shareSdk打包报错解决办法
    Android 事件分发机制
  • 原文地址:https://www.cnblogs.com/zhuxudong/p/10079511.html
Copyright © 2011-2022 走看看