LinkedBlockingQueue源码解析(3)

2018-12-18  本文已影响12人  yijian2595

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

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

4.3、public E take() throws InterruptedException

原理:

使用方法:

        try {
            abq.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

源代码:

    /**
     * 出队:
     * 如果队列空了,一直阻塞,直到队列不为空或者线程被中断
     */
    public E take() throws InterruptedException {
        E x;
        int c = -1;
        final AtomicInteger count = this.count;//获取队列中的元素总量
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();//获取出队锁
        try {
            while (count.get() == 0) {//如果没有元素,一直阻塞
                /*
                 * 加入等待队列, 一直等待条件notEmpty(即被其他线程唤醒)
                 * (唤醒其实就是,有线程将一个元素入队了,然后调用notEmpty.signal()唤醒其他等待这个条件的线程,同时队列也不空了)
                 */
                notEmpty.await();
            }
            x = dequeue();//出队
            c = count.getAndDecrement();//元素数量-1
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    }

 

总结:

1、具体入队与出队的原理图

图中每一个节点前半部分表示封装的数据x,后边的表示指向的下一个引用。

1.1、初始化

 初始化之后,初始化一个数据为null,且head和last节点都是这个节点。

1.2、入队两个元素过后

这个可以根据入队方法enqueue(E x)来看,源代码再贴一遍:

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

其实这我们就可以发现其实真正意义上出队的头节点是Head节点的下一个节点。(这也就是Node这个内部类中对next的注释,我没有翻译)

1.3、出队一个元素后

表面上看,只是将头节点的next指针指向了要删除的x1.next,事实上这样我觉的就完全可以,但是jdk实际上是将原来的head节点删除了,而上边看到的这个head节点,正是刚刚出队的x1节点,只是其值被置空了。

这一块对应着源代码来看:dequeue()

    /**
     * 从队列头部移除一个节点
     */
    private E dequeue() {
        Node<E> h = head;// 获取头节点:x==null
        Node<E> first = h.next;// 将头节点的下一个节点赋值给first
        h.next = h; // 将当前将要出队的节点置null(为了使其做head节点做准备)
        head = first;// 将当前将要出队的节点作为了头节点
        E x = first.item;// 获取出队节点的值
        first.item = null;// 将出队节点的值置空
        return x;
    }

 

2、三种入队对比:

 

3、三种出队对比:

 

4、ArrayBlockingQueue与LinkedBlockingQueue对比

 两个疑问:

这两个疑问,都是基于对于AtomicInteger的不熟,不明白LinkedBlockingQueue引用的这两个方法(getAndIncrement和getAndDecrement)先返回旧值还是新值,关于AtomicInteger的源码介绍,请查看《第十一章 AtomicInteger源码解析》,具体链接如下:

http://www.cnblogs.com/java-zhao/p/5140158.html

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

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

相关文章:
【推荐】 NOS直传加速服务
【推荐】 邪恶的三位一体:机器学习、黑暗网络和网络犯罪
【推荐】 致传统企业朋友:不够痛就别微服务,有坑 (2)

上一篇 下一篇

猜你喜欢

热点阅读