A.Q.S源码分析(shared模式下加锁)

shared模式下加锁和exclusive模式下加锁的机制大致相同,都是尝试加锁,如果失败那么入队阻塞的逻辑。

但是在获取到锁的逻辑有点区别:

private void doAcquireShared(int arg) {
        final Node node = addWaiter(Node.SHARED);
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } catch (RuntimeException ex) {
            cancelAcquire(node);
            throw ex;
        }
    }

重点是setHeadAndPropagate方法,在exclusive下只需要setHead就可以了,看下Propagate都做了些什么:

private void setHeadAndPropagate(Node node, int propagate) {
        Node h = head; // Record old head for check below
        setHead(node);
        /*
         * Try to signal next queued node if:
         * Propagation was indicated by caller,
         * or was recorded (as h.waitStatus) by a previous operation
         * (note: this uses sign-check of waitStatus because
         * PROPAGATE status may transition to SIGNAL.)
         * and
         * The next node is waiting in shared mode,
         * or we don't know, because it appears null
         *
         * The conservatism in both of these checks may cause
         * unnecessary wake-ups, but only when there are multiple
         * racing acquires/releases, so most need signals now or soon
         * anyway.
         */
        if (propagate > 0 || h == null || h.waitStatus < 0) { 
            Node s = node.next;
            if (s == null || s.isShared())
                doReleaseShared();
        }
    }

调用了doReleaseShared()方法,acquire方法最终调用了release方法,得看下为什么。原因其实也很简单,shared模式下是允许多个线程持有一把锁的,其中tryAcquire的返回值标志了是否允许其他线程继续进入。如果允许的话,需要唤醒队列中等待的线程。其中doReleaseShared方法的逻辑很简单,就是唤醒后继线程。这样就实现了Propagate的语义。

其中PROPAGATE = -3这个状态是个令人费解的状态,在早期的版本中是不存在这个状态的。这个状态的意思是即使tryAcquire返回值为0,那么也得去看下是不是需要唤醒后继结点。

因此acquire的主要逻辑就是尝试加锁,如果允许其他线程继续加锁,那么唤醒后继线程,如果失败,那么入队阻塞等待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值