AQS2--出队

设置前面=-1,就是为了当前面节点变成head执行唤醒时候,能够唤醒后面status正常的节点,

public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0) 
                unparkSuccessor(h);
Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev) 
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread);

一定要注意,前面节点变成head执行if (h != null && h.waitStatus != 0) 之前要设置为-1否则就不能唤醒后面status正常节点(除非后面节点自行出队)


 所以正常节点要阻塞之前设置-1.

上图中,A没有阻塞,head出队执行if (h != null && h.waitStatus != 0)时候可以=0可以=-1head=0出队就A自己去获取锁,head=-1出队唤醒A


 如果A阻塞了,就要异常的B去设置前面=-1,此时,一定要在异常节点B前面节点C出队执行if (h != null && h.waitStatus != 0) 之前把前面C设置-1如果前面节点出队时候=0A又阻塞了,A就永远获取不了锁,队列卡死。

但是,问题在于,正常节点和异常节点都无法知道前面节点是否已经出队执行过了if (h != null && h.waitStatus != 0)。但是前面节点变成head时候thread=null,所以后面节点能够知道的前面节点是否是head。所以一定要在异常节点B前面节点C变成head之前把前面C设置-1,否则就唤醒A

 下面看异常节点设置前面节点=-1逻辑:

if (pred != head
&&( (ws = pred.waitStatus) == Node.SIGNAL|| ( 
    ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) 
    && pred.thread != null 
                ) 
            {
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)
                    compareAndSetNext(pred, predNext, next);
            } else {
                unparkSuccessor(node);
            }
head = node;
node.thread = null;
node.prev = null;

1.如果异常节点前面节点=head

 此时不知道head有没有执行if (h != null && h.waitStatus != 0),如果没有执行,此时设置head=-1,那么head执行if (h != null && h.waitStatus != 0)就回去唤醒A,如果已经执行了,就不会唤醒任何节点,再去将head=-1,也没用,所以就去唤醒异常节点的后面节点。

2.如果C不是头节点,能够设置C=-1,并且设置C=-1之后C还不是头节点(C.thread != null),就建立后驱关系(即使还没有建好后驱关系,C就开始出队,但是C=-1了,C一定能够唤醒A)。这就保证了在异常节点B前面节点C变成head之前把前面C设置-1。其余情况都不行。

 如果异常节点前面C!=head,但是C=1了(此时C可以=head),肯定不能建立后驱关系,C节点就一定可以保证A能够唤醒,如果B再向前找没必要。B来唤醒,我个人感觉是没必要的,因为C可以一定唤醒A

 如果异常节点前面C!=headC没有异常(此时C可以=head),但是C是头节点了(C.thread = null),此时唤醒A

  

注意:C变成head,再去unlock执行if (h != null && h.waitStatus != 0)中间有很多时间。

猜你喜欢

转载自www.cnblogs.com/yaowen/p/11323457.html
AQS