AQS源码解析(中)

接上篇 AQS源码解析(上)

 private void cancelAcquire(Node node) {
        // Ignore if node doesn't exist
        if (node == null)
            return;

        node.thread = null;

        // Skip cancelled predecessors
        /**
         * 此处和shouldParkAfterFailedAcquire中的ws>0的情况类似 
         * 从当前节点往前遍历找到一个非取消状态的节点;
         * 注意此时当前节点的状态依然是合法状态还没被置为CANCELLED
         * 如果在下面操作之前就改为CANCELLED的话,那么就会和
         * shouldParkAfterFailedAcquire中的ws>0的情况有并发安全的问题;
         * 所以在找到一个合法节点以后才会改为CANCELLED,以防并发问题。
         */
        Node pred = node.prev;
        while (pred.waitStatus > 0)
            node.prev = pred = pred.prev;
		
       	//获取到当前节点pre节点的原next节点并保存以便于后面的CAS操作
        Node predNext = pred.next;
        

        // Can use unconditional write instead of CAS here.
        // After this atomic step, other Nodes can skip past us.
        // Before, we are free of interference from other threads.
        node.waitStatus = Node.CANCELLED;//此处才改为CANCELLED

        // If we are the tail, remove ourselves.
        /**
         * 如果当前节点是tail,那么cas替换tail
         * 如果成功的话,cas替换原predNext,这点考虑很充分,不愧大神
         * 因为有可能替换tail后,已经有waiter加入了,所以必须用cas
         */ 
        if (node == tail && compareAndSetTail(node, pred)) {
            compareAndSetNext(pred, predNext, null);
        } else {
            // If successor needs signal, try to set pred's next-link
            // so it will get one. Otherwise wake it up to propagate.
            /**
             * 下面的逻辑是考虑怎么把pred和node.next连接起来
             * 1.如果新pred不是头节点
             * 2.ws等于SIGNAL或者原来<=0并且cas成功变为SIGNAL,
             *   主要想把pred.ws设置为SIGNAL,以便于后续作为唤醒线程的标志。
             * 	 这里还要和共享模式下的doReleaseShared联系一下,因为此刻很可能
             * 	 已经传播到这里,其他线程刚把ws改为0并unpark,而这里又把ws改为SIGNAL,
             *   所以再次印证,一个线程可能会被多次unpark,不过不影响。
             * 3.pred.thread != null,再次判断pred是否已经唤醒并获取到资源
             * 上面三种情况都满足的情况下,进行设置pred.next=取消节点.next
             */ 
            int ws;
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {
                Node next = node.next;
                //检查此刻的next是否已经被取消
                if (next != null && next.waitStatus <= 0)
                    compareAndSetNext(pred, predNext, next);
            } else {
            	//如果pred已经是头节点
                unparkSuccessor(node);
            }

            node.next = node; // help GC
        }
    }
/**
 * 把条件队列的节点移动到同步队列中去进而排队等待资源
 */ 
final boolean transferForSignal(Node node) {
        /*
         * If cannot change waitStatus, the node has been cancelled.
         */
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;

        /*
         * Splice onto queue and try to set waitStatus of predecessor to
         * indicate that thread is (probably) waiting. If cancelled or
         * attempt to set waitStatus fails, wake up to resync (in which
         * case the waitStatus can be transiently and harmlessly wrong).
         */
         //这个enq方法返回的是加入到同步队列的pre节点
        Node p = enq(node);
        int ws = p.waitStatus;
        //如果此时节点已经取消或者节点的状态发生变化(比如传播或者唤醒)
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
    }
/**
 * 检测当前节点是否first节点
 * h != t 表明队列至少两个节点或者是两个节点的路上
 * h.next = null 在上一判断的基础上表明队列还没来得及给next赋值
 * s.thread != Thread.currentThread()表明first node不是自己
 */ 
 public final boolean hasQueuedPredecessors() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值