# ConcurrentLinkedQueue
# ConcurrentLinkedQueue
入队将节点放入队尾,出队将节点从队首移除
特性:
- 入队后不一定会修改tail指针
- 出队不一定会更新head指针
# 节点
# 入队
- 将入队节点设置到当前队尾节点的 next 节点上;
- 更新tail节点,
- 如果tail节点的next节点不为空,则将入队节点设置为 tail节点,
- 如果tail节点的next节点为空,则将入队节点设为tail节点的next节点。
public boolean offer(E e) {
...
final Node<E> newNode = new Node<E>(e);
for (Node<E> t = tail, p = t;;) {
Node<E> q = p.next;
if (q == null) {
if (p.casNext(null, newNode)) {
if (p != t)
casTail(t, newNode);
return true;
}
}
else if (p == q)
p = (t != (t = tail)) ? t : head;
else
p = (p != t && t != (t = tail)) ? t : q;
}
}
# 出队
head节点的元素
- 不为null,则弹出head中的元素,并设置head的元素为null,head指针不变
- 为null,更新head节点
public E poll() {
restartFromHead:
for (;;) {
for (Node<E> h = head, p = h, q;;) {
E item = 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;
}
else if ((q = p.next) == null) {
updateHead(h, p);
return null;
}
else if (p == q)
continue restartFromHead;
else
p = q;
}
}
}
- h节点在内循环中每次不会改变,而跳出内循环后再次进入h节点可能会变
- h节点是临时的head节点
- 每次从p节点cas成功更新元素后,要检查节点是否是h,不是则更新h为p的next或者p本身。
- h节点的元素为空,或CAS更改为空的时候失败,则看next节点,next节点为空,则队列为空,更改h节点,并返回null
- 第三分支:p=p.next,应该是p和p.next指针都被出队了,表明外部head已经变更,重新开始循环
- 第四分支:不是初始化,p指针前进一次