先看看其内部数据结构Node的实现。由于使用了原子字段更新器AtomicReferenceFieldUpdater<T,V>(其中T 表示持有字段的类的类型,V表示字段的类型),所以其对应的需要更新的字段要使用volatile进行声明。其 newUpdater(Class<U> tclass, Class<W> vclass, String fieldName)方法实例化一个指定字段的更新器,参数分别表示:持有需要更新字段的类,字段的类,要更新的字段的名称。Node的内部变量 item,next分别有对应自己的字段更新器,并且包含了对其原子性操作的方法compareAndSet(T obj, V expect, V update),其中T是持有被设置字段的对象,后两者分别是期望值和新值。public class ConcurrentLinkedQueue<E> extends AbstractQueue<E> implements Queue<E>, java.io.Serializable { private static final long serialVersionUID = 196745693267521676L; private static class Node<E> { private volatile E item; private volatile Node<E> next; private static final AtomicReferenceFieldUpdater<Node, Node> nextUpdater = AtomicReferenceFieldUpdater.newUpdater (Node.class, Node.class, "next"); private static final AtomicReferenceFieldUpdater<Node, Object> itemUpdater = AtomicReferenceFieldUpdater.newUpdater (Node.class, Object.class, "item"); Node(E x) { item = x; } Node(E x, Node<E> n) { item = x; next = n; } E getItem() { return item; } boolean casItem(E cmp, E val) { return itemUpdater.compareAndSet(this, cmp, val); } void setItem(E val) { itemUpdater.set(this, val); } Node<E> getNext() { return next; } boolean casNext(Node<E> cmp, Node<E> val) { return nextUpdater.compareAndSet(this, cmp, val); } void setNext(Node<E> val) { nextUpdater.set(this, val); } } private static final AtomicReferenceFieldUpdater<ConcurrentLinkedQueue, Node> tailUpdater = AtomicReferenceFieldUpdater.newUpdater (ConcurrentLinkedQueue.class, Node.class, "tail"); private static final AtomicReferenceFieldUpdater<ConcurrentLinkedQueue, Node> headUpdater = AtomicReferenceFieldUpdater.newUpdater (ConcurrentLinkedQueue.class, Node.class, "head"); private boolean casTail(Node<E> cmp, Node<E> val) { return tailUpdater.compareAndSet(this, cmp, val); } private boolean casHead(Node<E> cmp, Node<E> val) { return headUpdater.compareAndSet(this, cmp, val); } private transient volatile Node<E> head = new Node<E>(null, null); private transient volatile Node<E> tail = head; ... }
public boolean offer(E e) { if (e == null) throw new NullPointerException(); Node<E> n = new Node<E>(e, null); for (;;) { Node<E> t = tail; Node<E> s = t.getNext(); if (t == tail) { //------------------------------a if (s == null) { //---------------------------b if (t.casNext(s, n)) { //-------------------c casTail(t, n); //------------------------d return true; } } else { casTail(t, s); //----------------------------e } } } }offer()方法都很熟悉了,就是入队的操作。涉及到改变尾指针的操作,所以要看这个方法实现是否保证了原子性。CAS操作配合循环是原子性操作的保 证,这里也不例外。此方法的循环内首先获得尾指针和其next指向的对象,由于tail和Node的next均是volatile的,所以保证了获得的分 别都是最新的值。
Node<E> first() { for (;;) { Node<E> h = head; Node<E> t = tail; Node<E> first = h.getNext(); if (h == head) { //---------------------------------------a if (h == t) { //-----------------------------------------b if (first == null) //----------------------------------c return null; else casTail(t, first); //--------------------------------d } else { if (first.getItem() != null) //------------------------e return first; else // remove deleted node and continue casHead(h, first); //------------------------------f } } } }此方法在尝试获得最新的第一个非head结点的时候,在不同的阶段同样在协调着head和tail的更新任务,让人感觉无锁的世界没有纯粹的工作,呵呵。