视频课程
小黑屋思过中,禁止观看!
评论并刷新后可见

您需要在视频最下面评论并刷新后,方可查看完整视频

视频课程
立即观看
付费视频

您支付费用,方可查看完整视频

¥{{user.role.value}}
课程视频
开始学习
会员专享

视频合集

ConcurrentLinkedQueue深度源码剖析

  • 课程笔记
  • 问答交流

并发队列:阻塞与非阻塞队列详解,分别谈到了实现并发队列的两种方式。
方式1:加锁,这种实现方式就是我们常说的阻塞队列。
方式2:使用循环CAS算法实现,这种方式实现队列称之为非阻塞队列。

为了助大家掌握好非阻塞队列,这节课我会重点来讲解ConcurrentLinkedQueue,包含以下5点:

1.ConcurrentLinkedQueue介绍

2.ConcurrentLinkedQueue的数据结构

3.ConcurrentLinkedQueue构造函数

4.ConcurrentLinkedQueue的核心实现

5.ConcurrentLinkedQueue的线程安全

ConcurrentLinkedQueue

ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部,当我们获取一个元素时,它会返回队列头部的元素。

注意:在判断ConcurrentLinkedQueue非空时,不要使用size()==0的做法,因为size()方法中,是通过遍历整个链表来实现的,在队列元素很多的时候,此方法非常消耗性能和时间,只是单纯判断队列为空使用isEmpty()即可。

ConcurrentLinkedQueue的数据结构

ConcurrentLinkedQueue深度源码剖析-mikechen

核心源码

public class ConcurrentLinkedQueue<E> extends AbstractQueue<E>
    implements Queue<E>, java.io.Serializable {
    /**
     * 队列头指针
     */
    private transient volatile Node<E> head;
    /**
     * 队列尾指针.
     */
    private transient volatile Node<E> tail;
    // Unsafe mechanics
     
    private static final sun.misc.Unsafe UNSAFE;
    private static final long headOffset;
    private static final long tailOffset;
     
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> k = ConcurrentLinkedQueue.class;
            headOffset = UNSAFE.objectFieldOffset (k.getDeclaredField("head"));
            tailOffset = UNSAFE.objectFieldOffset (k.getDeclaredField("tail"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }
    /**
     * 队列结点定义
     */
    private static class Node<E> {
        volatile E item;        // 元素值
        volatile Node<E> next;  // 后驱指针
        Node(E item) {
            UNSAFE.putObject(this, itemOffset, item);
        }
        boolean casItem(E cmp, E val) {
            return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
        }
        void lazySetNext(Node<E> val) {
            UNSAFE.putOrderedObject(this, nextOffset, val);
        }
        boolean casNext(Node<E> cmp, Node<E> val) {
            return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
        }
        // Unsafe mechanics
        private static final sun.misc.Unsafe UNSAFE;
        private static final long itemOffset;
        private static final long nextOffset;
        static {
            try {
                UNSAFE = sun.misc.Unsafe.getUnsafe();
                Class<?> k = Node.class;
                itemOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("item"));
                nextOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("next"));
            } catch (Exception e) {
                throw new Error(e);
            }
        }
    }
    //...
}
评论交流
  1. 李鸿翼

    入队的核心思想:
    (1)基于自旋方式,找到队列的真正尾部,然后添加节点,其中设置tail标志符号,有延迟性。
    (2)当存在延迟性的时候,就会找真正的尾部,最后把新添加的节点设置为尾部
    (3)如果添加节点过程中,有另外一个线程poll节点,会知道p==q,如果尾部节点都发生了变化,把p指向head节点,如果尾部节点没有变化,p还是指向尾部节点

  2. 路正银

    非阻塞队列ConcurrentLinkedQueue入队流程如下: