ConcurrentLinkedQueue不同于LinkedBlockingQueue,它没有利用ReentranLock以及Condition条件。而是利用死循环+CAS来实现线程安全,也就是一个重试的机制。
ConcurrentLinkedQueue是一个无阻塞的高效的队列。
ConcurrentLinkedQueue是基于单向链表的。
public class ConcurrentLinkedQueue extends AbstractQueue
implements Queue, java.io.Serializable {
// 单向链表,对节点的操作都是基于Unsafe的原子操作
private static class Node {
volatile E item;
volatile Node next;
/**
* Constructs a new node. Uses relaxed write because item can
* only be seen after publication via casNext.
*/
Node(E item) {
UNSAFE.putObject(this, itemOffset, item);
}
boolean casItem(E cmp, E val) {
return UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
}
void lazySetNext(Node val) {
UNSAFE.putOrderedObject(this, nextOffset, val);
}
boolean casNext(Node cmp, Node 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);
}
}
}
/**
* A node from which the first live (non-deleted) node (if any)
* can be reached in O(1) time.
* Invariants:
* - all live nodes are reachable from head via succ()
* - head != null
* - (tmp = head).next != tmp || tmp != head
* Non-invariants:
* - head.item may or may not be null.
* - it is permitted for tail to lag behind head, that is, for tail
* to not be reachable from head!
*/
// 头节点
private transient volatile Node head;
/**
* A node from which the last node on list (that is, the unique
* node with node.next == null) can be reached in O(1) time.
* Invariants:
* - the last node is always reachable from tail via succ()
* - tail != null
* Non-invariants:
* - tail.item may or may not be null.
* - it is permitted for tail to lag behind head, that is, for tail
* to not be reachable from head!
* - tail.next may or may not be self-pointing to tail.
*/
// 尾节点
private transient volatile Node tail;
/**
* Creates a {@code ConcurrentLinkedQueue} that is initially empty.
*/
public ConcurrentLinkedQueue() {
head = tail = new Node(null);
}
// 插入一个元素到尾节点
public boolean offer(E e) {
// 检查插入的元素非空
checkNotNull(e);
// 新建一个节点
final Node newNode = new Node(e);
// 死循环,尾节点给t,t给p
for (Node t = tail, p = t;;) {
// 取出p的下一个节点,在单线程下应该是null,多线程情况下,又没有加锁,所以就会有
// elseif或else的情况
Node q = p.next;
// 如果q=null,说明此刻p还是满足最后一个节点的条件
if (q == null) {
// p is last node
// 原子的设置p的下一个节点为新节点newNode
if (p.casNext(null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this queue,
// and for newNode to become "live".
// 如果设置成功了,再次检查p还是不是尾节点,如果不是就设置尾节点为newNode
// 理论上说不是了,因为p的next已经不是null,但是要是newNode被gc了就不一定
if (p != t) // hop two nodes at a time
casTail(t, newNode); // Failure is OK.
// 这里可以直接返回true是因为上面cas就算失败,其实也就是把null放到tail的
// next,和原来一样
return true;
}
// Lost CAS race to another thread; re-read next
}
//
else if (p == q)
// 此时,若尾节点没有发生变化的话,那么,应该是头节点发生了变化,则设置p为头节
// 点,然后重新遍历链表;否则(尾节点变化的话),则设置p为尾节点
// We have fallen off list. If tail is unchanged, it
// will also be off-list, in which case we need to
// jump to head, from which all live nodes are always
// reachable. Else the new tail is a better bet.
p = (t != (t = tail)) ? t : head;
else
// 如果p和t相等,则设置p为q。否则的话,判断“尾节点是否发生变化”,没有变化的话,
// 则设置p为q;否则,设置p为尾节点。
// Check for tail updates after two hops.
p = (p != t && t != (t = tail)) ? t : q;
}
}
// 取出头节点并删除
public E poll() {
// 打了一个lable
restartFromHead:
for (;;) {
for (Node h = head, p = h, q;;) {
E item = p.item;
// 设置头节点的值为null
if (item != null && p.casItem(item, null)) {
// Successful CAS is the linearization point
// for item to be removed from this queue.
// 如果p已经不是头节点了,就更新头节点为原来头节点的下一个节点
if (p != h) // hop two nodes at a time
updateHead(h, ((q = p.next) != null) ? q : p);
return item;
}
// 表头的下一个节点为null,即链表只有一个“内容为null的表头节点”。则更新表头
// 为p,并返回null。
else if ((q = p.next) == null) {
updateHead(h, p);
return null;
}
// 这可能到由于else的发生导致p=q,在该情况下跳转到restartFromHead标记重新操作
else if (p == q)
continue restartFromHead;
else
p = q;
}
}
}
/**
* Tries to CAS head to p. If successful, repoint old head to itself
* as sentinel for succ(), below.
*/
final void updateHead(Node h, Node p) {
if (h != p && casHead(h, p))
h.lazySetNext(h);
}
}