线程安全(十一)ConcurrentLinkedQueue的原理以及CAS机制在其中的应用

系列文章目录

线程安全(一)java对象头分析以及锁状态
线程安全(二)java中的CAS机制
线程安全(三)实现方法sychronized与ReentrantLock(阻塞同步)
线程安全(四)Java内存模型与volatile关键字
线程安全(五)线程状态和线程创建
线程安全(六)线程池
线程安全(七)ThreadLocal和java的四种引用
线程安全(八)Semaphore
线程安全(九)CyclicBarrier
线程安全(十)AQS(AbstractQueuedSynchronizer)
线程安全(十一)ConcurrentLinkedQueue的原理以及CAS机制在其中的应用

0.前言

ConcurrentLinkedQueue是一个线程安全队列,区别于阻塞算法的锁机制,它使用了基于CAS机制的非阻塞算法。

1.队列

队列:通常(但并非一定)以 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

2.CAS机制

之前文章说明过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);
            }
        }
    }

3.源码解析

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;
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值