zoukankan      html  css  js  c++  java
  • LinkedBlockingQueue源码解析(1)

    此文已由作者赵计刚授权网易云社区发布。

    欢迎访问网易云社区,了解更多网易技术产品运营经验。


    1、对于LinkedBlockingQueue需要掌握以下几点

    • 创建

    • 入队(添加元素)

    • 出队(删除元素)

    2、创建

    Node节点内部类与LinkedBlockingQueue的一些属性

        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; }
        }
    
        /** 指定链表容量  */
        private final int capacity;
    
        /** 当前的元素个数 */
        private final AtomicInteger count = new AtomicInteger(0);
    
        /** 链表头节点 */
        private transient Node<E> head;
    
        /** 链表尾节点 */
        private transient Node<E> last;
    
        /** 出队锁 */
        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.1、public LinkedBlockingQueue(int capacity)

    使用方法:

    Queue<String> abq = new LinkedBlockingQueue<String>(1000);

    源代码:

        /**
         * 创建一个 LinkedBlockingQueue,容量为指定容量
         */
        public LinkedBlockingQueue(int capacity) {
            if (capacity <= 0) throw new IllegalArgumentException();
            this.capacity = capacity;
            last = head = new Node<E>(null);//初始化头节点和尾节点,均为封装了null数据的节点
        }

    注意点:

    • LinkedBlockingQueue的组成一个链表+两把锁+两个条件

     

    2.2、public LinkedBlockingQueue()

    使用方法:

    Queue<String> abq = new LinkedBlockingQueue<String>();

    源代码:

        /**
         * 创建一个LinkedBlockingQueue,容量为整数最大值
         */
        public LinkedBlockingQueue() {
            this(Integer.MAX_VALUE);
        }

    注意点:默认容量为整数最大值,可以看做没有容量限制

     

    3、入队:

    3.1、public boolean offer(E e)

    原理:

    • 在队尾插入一个元素, 如果队列没满,立即返回true; 如果队列满了,立即返回false

    使用方法:

    • abq.offer("hello1");

    源代码:

        /**
         * 在队尾插入一个元素, 容量没满,可以立即插入,返回true; 队列满了,直接返回false
         * 注:如果使用了限制了容量的队列,这个方法比add()好,因为add()插入失败就会抛出异常
         */
        public boolean offer(E e) {
            if (e == null)
                throw new NullPointerException();
            final AtomicInteger count = this.count;// 获取队列中的元素个数
            if (count.get() == capacity)// 队列满了
                return false;
            int c = -1;
            final ReentrantLock putLock = this.putLock;
            putLock.lock();// 获取入队锁
            try {
                if (count.get() < capacity) {// 容量没满
                    enqueue(e);// 入队
                    c = count.getAndIncrement();// 容量+1,返回旧值(注意)
                    if (c + 1 < capacity)// 如果添加元素后的容量,还小于指定容量(说明在插入当前元素后,至少还可以再插一个元素)
                        notFull.signal();// 唤醒等待notFull条件的其中一个线程
                }
            } finally {
                putLock.unlock();// 释放入队锁
            }
            if (c == 0)// 如果c==0,这是什么情况?一开始如果是个空队列,就会是这样的值,要注意的是,上边的c返回的是旧值
                signalNotEmpty();
            return c >= 0;
        }

        /**
         * 创建一个节点,并加入链表尾部
         * @param x
         */
        private void enqueue(E x) {
            /*
             * 封装新节点,并赋给当前的最后一个节点的下一个节点,然后在将这个节点设为最后一个节点
             */
            last = last.next = new Node<E>(x);
        }

        private void signalNotEmpty() {
            final ReentrantLock takeLock = this.takeLock;
            takeLock.lock();//获取出队锁
            try {
                notEmpty.signal();//唤醒等待notEmpty条件的线程中的一个
            } finally {
                takeLock.unlock();//释放出队锁
            }
        }

    如果,入队逻辑不懂,查看最后总结部分入队逻辑的图,代码非常简单,流程看注释即可。

     

    3.2、public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException

    原理:

    • 在队尾插入一个元素,,如果队列已满,则进入等待,直到出现以下三种情况:

      • 被唤醒

      • 等待时间超时

      • 当前线程被中断

    使用方法:

            try {
                abq.offer("hello2",1000,TimeUnit.MILLISECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

    源代码:

        /**
         * 在队尾插入一个元素,,如果队列已满,则进入等待,直到出现以下三种情况: 
         * 1、被唤醒 
         * 2、等待时间超时 
         * 3、当前线程被中断
         */
        public boolean offer(E e, long timeout, TimeUnit unit)
                throws InterruptedException {
    
            if (e == null)
                throw new NullPointerException();
            long nanos = unit.toNanos(timeout);// 转换为纳秒
            int c = -1;
            final ReentrantLock putLock = this.putLock;// 入队锁
            final AtomicInteger count = this.count;// 总数量
            putLock.lockInterruptibly();
            try {
                while (count.get() == capacity) {// 容量已满
                    if (nanos <= 0)// 已经超时
                        return false;
                    /*
                     * 进行等待: 在这个过程中可能发生三件事: 
                     * 1、被唤醒-->继续当前这个while循环
                     * 2、超时-->继续当前这个while循环 
                     * 3、被中断-->抛出中断异常InterruptedException
                     */
                    nanos = notFull.awaitNanos(nanos);
                }
                enqueue(e);// 入队
                c = count.getAndIncrement();// 入队元素数量+1
                if (c + 1 < capacity)
                    notFull.signal();
            } finally {
                putLock.unlock();
            }
            if (c == 0)
                signalNotEmpty();
            return true;
        }

    注意:

    • awaitNanos(nanos)是AQS中的一个方法,这里就不详细说了,有兴趣的自己去查看AQS的源代码。


    免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐

    更多网易技术、产品、运营经验分享请点击


    相关文章:
    【推荐】 面对内容监管,短视频平台如何“翩翩起舞”,这有5条中肯建议
    【推荐】 小企业需要数据分析吗?

  • 相关阅读:
    Leetcode Substring with Concatenation of All Words
    Leetcode Divide Two Integers
    Leetcode Edit Distance
    Leetcode Longest Palindromic Substring
    Leetcode Longest Substring Without Repeating Characters
    Leetcode 4Sum
    Leetcode 3Sum Closest
    Leetcode 3Sum
    Leetcode Candy
    Leetcode jump Game II
  • 原文地址:https://www.cnblogs.com/zyfd/p/10137337.html
Copyright © 2011-2022 走看看