ConcurrentLinkedQueue的原理以及CAS机制在其中的应用

来源:互联网 发布:kindle电子书编辑软件 编辑:程序博客网 时间:2024/04/19 21:19

ConcurrentLinkedQueue是一个线程安全队列,区别于阻塞算法的锁机制,它使用了基于CAS机制的非阻塞算法。
基本概念介绍:
队列:通常(但并非一定)以 FIFO(先进先出)的方式排序各个元素。
接口Queue

接口quque中的方法可以分为三类添加队列尾元素  boolean add(E e)与boolean offer(E e)add结果只能为返回true(成功插入)或抛出异常(不成功),根据异常类型(IllegalStateException)才能看出是否由于对列容量限制offer结果返回true(成功插入)或返回false(容量限制)或抛出异常获取队列头但不移除  E element() 与 E peek()区别在于当队列为空时 elemnet()方法抛出异常peek方法返回null获取对列头并移除remove() 与 poll()区别在于队列为空时 remove()方法抛出异常poll方法返回null

之前文章说明过CAS机制的依据(硬件层面的是实现):http://blog.csdn.net/do_finsh/article/details/78773573
以及大体java.util.concurrent包下的类实现的共同点:

  1. .声明共享变量为volatile;(没有原子性,有可见性)
  2. 使用CAS的原子条件更新来实现线程之间的同步;
  3. 配合以volatile的读/写和CAS所具有的volatile读和写的内存语义来实现线程之间的通信。

现在具体说明一下ConcurrentLinkedQueue中的应用

首先出现了一个私有静态类Node
这个Node类中出现了UNSAFE类,节点类Node< E> 通过UNSAFE类的方法,进行CAS操作。大致了解一下
UNSAFE类的方法

    // 获取f在堆内存的偏移地址    public native long objectFieldOffset(Field f);    // 获取静态f在堆内存的偏移地址    public native long staticFieldOffset(Field f);    // 原子的更改offset地址的变量。如果变量的值为expected,并成功替换为x 返回true  CAS操作    public final native boolean compareAndSwapObject(Object o, long offset, Object expected,Object x);    // 将offset地址的值替换为x,并且通知其他线程。因为有Volatile,与putObject类似    public native void putObjectVolatile(Object o, long offset, Object x);    // 获取地址为offset 的值    public native Object getObjectVolatile(Object o, long offset)   /**     * Version of {@link #putObjectVolatile(Object, long, Object)}     * that does not guarantee immediate visibility of the store to     * other threads. This method is generally only useful if the     * underlying field is a Java volatile (or if an array cell, one     * that is otherwise only accessed using volatile accesses).     */public native void putOrderedObject(Object o, long offset, Object x);

节点类Node

private static class Node<E> {        volatile E item; // volatile声明        volatile Node<E> next; // volatile声明        // 构造方法  在地址itemOffset处, 值替换为item        Node(E item) {            UNSAFE.putObject(this, itemOffset, item);        }        // CAS操作:比较并交换,原子的更改itemOffset地址的变量。如果变量的值为cmp,并成功替换为val 返回true          boolean casItem(E cmp, E val) {            return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);        }       // 将nextOffset地址的值替换为x        void lazySetNext(Node<E> val) {            UNSAFE.putOrderedObject(this, nextOffset, val);        }        // CAS操作:比较并交换,原子的更改nextOffset地址的变量。如果变量的值为cmp,并成功替换为val 返回true        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;        /**          * 静态代码块,获取itemOffset和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);            }        }    }

ConcurrentLinkedQueue的常用方法offer(E e);

public boolean offer(E e) {        checkNotNull(e);        //创建一个入队节点        final Node<E> newNode = new Node<E>(e);        // 死循环,直到return ture         // 创建一个指向tail节点的引用t        // p用来表示尾结点        for (Node<E> t = tail, p = t;;) {             // 获取p的下一节点            Node<E> q = p.next;            // 如果q为空,说明p是尾节点            if (q == null) {                // p是尾节点,把e放入p节点之后,CAS操作(原子性操作),成功,跳出循环                if (p.casNext(null, newNode)) {                    if (p != t)                     // 如果tail不是尾节点则将入队节点设置为tail。如果失败了,那么说明有其他线程已经把tail移动过                        casTail(t, newNode);                     return true;                }            }            // 如果p节点等于p的next节点,则说明p节点和q节点都为空,表示队列刚初始化,所以返回             else if (p == q)                p = (t != (t = tail)) ? t : head;            else                //p有next节点,表示p的next节点是尾节点,则需要重新更新p后将它指向next节点                //此步判断非原子性操作t != (t = tail)                p = (p != t && t != (t = tail)) ? t : q;        }    }
原创粉丝点击