Java多线程系列--“JUC集合”10之 ConcurrentLinkedQueue(二)

2014-11-24 02:55:18 · 作者: · 浏览: 2
entLinkedQueue中的添加进行说明。
public boolean add(E e) {
return offer(e);
}
说明:add()实际上是调用的offer()来完成添加操作的。
offer()的源码如下:
复制代码
public boolean offer(E e) {
// 检查e是不是null,是的话抛出NullPointerException异常。
checkNotNull(e);
// 创建新的节点
final Node newNode = new Node(e);
// 将“新的节点”添加到链表的末尾。
for (Node t = tail, p = t;;) {
Node q = p.next;
// 情况1:q为空
if (q == null) {
// CAS操作:如果“p的下一个节点为null”(即p为尾节点),则设置p的下一个节点为newNode。
// 如果该CAS操作成功的话,则比较“p和t”(若p不等于t,则设置newNode为新的尾节点),然后返回true。
// 如果该CAS操作失败,这意味着“其它线程对尾节点进行了修改”,则重新循环。
if (p.casNext(null, newNode)) {
if (p != t) // hop two nodes at a time
casTail(t, newNode); // Failure is OK.
return true;
}
}
// 情况2:p和q相等
else if (p == q)
p = (t != (t = tail)) t : head;
// 情况3:其它
else
p = (p != t && t != (t = tail)) t : q;
}
}
复制代码
说明:offer(E e)的作用就是将元素e添加到链表的末尾。offer()比较的地方是理解for循环,下面区分3种情况对for进行分析。
情况1 -- q为空。这意味着q是尾节点的下一个节点。此时,通过p.casNext(null, newNode)将“p的下一个节点设为newNode”,若设置成功的话,则比较“p和t”(若p不等于t,则设置newNode为新的尾节点),然后返回true。否则的话(意味着“其它线程对尾节点进行了修改”),什么也不做,继续进行for循环。
p.casNext(null, newNode),是调用CAS对p进行操作。若“p的下一个节点等于null”,则设置“p的下一个节点等于newNode”;设置成功的话,返回true,失败的话返回false。
情况2 -- p和q相等。这种情况什么时候会发生呢?通过“情况3”,我们知道,经过“情况3”的处理后,p的值可能等于q。
此时,若尾节点没有发生变化的话,那么,应该是头节点发生了变化,则设置p为头节点,然后重新遍历链表;否则(尾节点变化的话),则设置p为尾节点。
情况3 -- 其它。
我们将p = (p != t && t != (t = tail)) t : q;转换成如下代码。
复制代码
if (p==t) {
p = q;
} else {
Node tmp=t;
t = tail;
if (tmp==t) {
p=q;
} else {
p=t;
}
}
复制代码
如果p和t相等,则设置p为q。否则的话,判断“尾节点是否发生变化”,没有变化的话,则设置p为q;否则,设置p为尾节点。
checkNotNull()的源码如下:
private static void checkNotNull(Object v) {
if (v == null)
throw new NullPointerException();
}
3. 删除
下面以poll()为例对ConcurrentLinkedQueue中的删除进行说明。
复制代码
public E poll() {
// 设置“标记”
restartFromHead:
for (;;) {
for (Node h = head, p = h, q;;) {
E item = p.item;
// 情况1
// 表头的数据不为null,并且“设置表头的数据为null”这个操作成功的话;
// 则比较“p和h”(若p!=h,即表头发生了变化,则更新表头,即设置表头为p),然后返回原表头的item值。
if (item != null && p.casItem(item, null)) {
if (p != h) // hop two nodes at a time
updateHead(h, ((q = p.next) != null) q : p);
return item;
}
// 情况2
// 表头的下一个节点为null,即链表只有一个“内容为null的表头节点”。则更新表头为p,并返回null。
else if ((q = p.next) == null) {
updateHead(h, p);
return null;
}
// 情况3
// 这可能到由于“情况4”的发生导致p=q,在该情况下跳转到restartFromHead标记重新操作。
else if (p == q)
continue restartFromHead;
// 情况4
// 设置p为q
else
p = q;
}
}
}
复制代码
说明:poll()的作用就是删除链表的表头节点,并返回被删节点对应的值。poll()的实现原理和offer()比较类似,下面根将or循环划分为4种情况进行分析。
情况1:“表头节点的数据”不为null,并且“设置表头节点的数据为null”这个操作成功。
p.casItem(item, null) -- 调用CAS函数,比较“节点p的数据值”与item是否相等,是的话,设置节点p的数据值为null。
在情况1发生时,先比较“p和h”,若p!=h,即表头发生了变化,则调用updateHead()更新表头;然后返回删除节点的item值。
updateHead()的源码如下:
final void updateHead(Node h, Node p) {
if (h != p && casHead(h, p))
h.lazySe