来看一下线程安全的队列无界队列ConcurrentLinkedQueue 先来看一下成员变量和构造函数吧
private static class Node<E> {
volatile E item;
volatile Node<E> next
}
private transient volatile Node<E> head;
private transient volatile Node<E> tail;
public ConcurrentLinkedQueue() {
head = tail = new Node<E>(null);
}
一个内部类Node,只有next指针,说明是单向链表 一个头指针,一个尾指针 构造方法会生成一个空Node,head和tail指针都指向空Node
假设queue.offer("a"),来看看是如何入队的
public boolean offer(E e) {
checkNotNull(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) // hop two nodes at a time
casTail(t, newNode); // Failure is OK.
return true;
}
}
else if (p == q)
p = (t != (t = tail)) ? t : head;
else
p = (p != t && t != (t = tail)) ? t : q;
}
}
又是一个无限for循环,这个套路已经很常见了。 首先为元素a生成一个Node,然后把t指向tail,p指向t,此时p,t,head,tail都指向了空Node。q又指向p的next,p的next是空,即q==null。p.casNext(null, newNode)哟,这里用了CAS诶,把node a放到空Node的后面。看来是用CAS来保证插入的线程安全,现在p和t还都指向空Node,所以直接返回true,插入成功
此时又queue.offer("b"): q=p.next=Node a,q!=null,p!=q,走p = (p != t && t != (t = tail)) ? t : q;此时p=t还都指向着空Node,false即p=q都指向Node a。进去下一次for循环,p=q.next,p==null,CAS把Node b插入到Node a后面,并将tail指针指向Node b,返回true
看完了入队,再来看看出队 queue.poll()
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;
}
}
}
只要就是CAS把头结点Node a的item置为null,把head指针从指向Node null,移除空Node,返回item "a"
趁热打铁来看看queue.size()
public int size() {
int count = 0;
for (Node<E> p = first(); p != null; p = succ(p))
if (p.item != null)
// Collection.size() spec says to max out
if (++count == Integer.MAX_VALUE)
break;
return count;
}
这边只是直接遍历了一下,累加得出了size。在执行size()时,刚好有入队操作呢,是不是就会存在数据一致性问题了呢