关于Java并发包下AQS队列的一点点看法
No-Blocking算法(简称NB)作为科研的主题已经有20年了,但直到1.5才被大量线上应用;
我们第一次见到CAS估计都是从那个++引入的:用AtomicInteger和带synchronized关键字的++比看谁加到1000用的时间更少,于是凭借这个小小的volatile int变量我们也就达到了把锁的粒度降到最低、进而达到高并发的目的,然而如果没有CLH队列的保证n个线程疯抢一把对象锁也是很悲剧的。
进队出队也需要CAS操作,但是没那么简单了.......昨天在看AbstractQueuedSynchronizer源码时发现了一个问题,特此拿出来讨论讨论:
private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode);//构造代表入队线程的节点 Node pred = tail;//读取CLH队列最后一个节点(尾指针) if (pred != null) { node.prev = pred;//CLH是双向链表,但此步不足以入队//如果从行3到这里尾指针没被其他线程碰过就把尾指针指向入队的那个节点 if (compareAndSetTail(pred, node)) { pred.next = node;//此步足以入队 return node; } } enq(node);//如果能执行到这里我就有话要说了,且听下文分解 return node; }private Node enq(final Node node) { for (;;) { Node t = tail;//再次读取最后一个节点 if (t == null) { //当且仅当CLH是空的时候t才会为null Node h = new Node(); //传说中的头结点(其实是个傀儡节点) h.next = node; node.prev = h;//入队的节点排在头结点之后 if (compareAndSetHead(h)) { tail = node; return h; } } else { node.prev = t; if (compareAndSetTail(t, node)) { t.next = node; return t; } } } }lastNode.next=newNode;newNode.pre=lastNode;
if(tail.next==null){...public Node addWaiter(Node newNode) { while (true) { if (tail.next == null) {//看起来很“废”的判断 if (tail.next.CAS(null, newNode)) {//完成入队 CAStail(tail, newNode);//刷新尾指针 return newNode; } }else{ CAStail(tail,tail.next);//让队列回到一致状态 } }}