AQS笔记之共享式获取同步状态

导览

不响应中断

acquireShared方法

public final void acquireShared(int arg) {
        //tryAcquireShared尝试获取共享式同步状态(需重写)
        // 负数:表示获取失败
        // 零值:表示当前结点获取成功, 但是后继结点不能再获取了
        // 正数:表示当前结点获取成功, 并且后继结点同样可以获取成功
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);//获取失败则将当前线程构造成节点放入同步队列
}

查看doAcquireShared方法

doAcquireShared方法

private void doAcquireShared(int arg) {
        final Node node = addWaiter(Node.SHARED);//将当前线程构造成共享式节点放入同步队列
        boolean interrupted = false;
        try {
            for (;;) {
                final Node p = node.predecessor();
                //若前驱节点为头结点则尝试获取同步状态
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {//同步状态获取成功
                        setHeadAndPropagate(node, r);//设置头结点,传播同步状态(共享式获取同步状态的核心之一)
                        p.next = null; // help GC
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node))//获取失败后,判断是否可将线程阻塞(挂起)
                    interrupted |= parkAndCheckInterrupt();
            }
        } catch (Throwable t) {
            cancelAcquire(node);
            throw t;
        } finally {
            if (interrupted)
                selfInterrupt();
        }
}

查看addWaiter方法setHeadAndPropagate方法shouldParkAfterFailedAcquire方法parkAndCheckInterrupt方法cancelAcquire方法
此方法acquireShared方法被调用

setHeadAndPropagate方法

/**
  * Sets head of queue, and checks if successor may be waiting
  * in shared mode, if so propagating if either propagate > 0 or
  *  PROPAGATE status was set.
  * 
  *  @param node the node
  *  @param propagate the return value from a tryAcquireShared
  * */
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 either before
         *     or after setHead) 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 ||
            (h = head) == null || h.waitStatus < 0) {
            Node s = node.next;
            if (s == null || s.isShared())//当前节点线程的后继节点为空或者为共享类型
                doReleaseShared();//唤醒下一个节点(共享式获取同步状态的核心之二)
        }
}

查看doReleaseShared方法
此方法doAcquireShared方法doAcquireSharedNanos方法acquireSharedInterruptibly方法被调用

releaseShared方法

public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {//尝试释放共享式同步状态(修改共享式同步状态),释放成功返回true,否则返回false
            doReleaseShared();
            return true;
        }
        return false;
}

查看doReleaseShared方法

doReleaseShared方法

private void doReleaseShared() {
        /*
         * Ensure that a release propagates, even if there are other
         * in-progress acquires/releases.  This proceeds in the usual
         * way of trying to unparkSuccessor of head if it needs
         * signal. But if it does not, status is set to PROPAGATE to
         * ensure that upon release, propagation continues.
         * Additionally, we must loop in case a new node is added
         * while we are doing this. Also, unlike other uses of
         * unparkSuccessor, we need to know if CAS to reset status
         * fails, if so rechecking.
         */
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                //由于共享式同步状态释放可能存在多个线程同时释放,所以要采用CAS操作
                if (ws == Node.SIGNAL) {//表明后面有节点需要唤醒
                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    //若CAS操作成功则唤醒后继节点,随后后继节点会在doAcquireShared方法中将自己设置为头结点,完成一次传播
                    unparkSuccessor(h);
                }
                //若头结点为初始状态(即在当前线程之后没有其他线程获取过同步状态,包括独享式同步状态获取,因为同步队列中未取
                //消获取锁的线程节点都会由后继节点将其状态设置为SIGNAL,以便当前线程释放同步状态后能够唤醒自己,即对应于
                //doAcquireShared方法中s==null的情况)则将其变为PROPAGATE,以确保下一次共享状态传播。
                //例如,当前线程获取到同步式共享状态之后,在未释放之前的某个时间有其他线程来获取同步状态,那么在重写
                //tryAcquireShared方法的时候,就可以直接通过判断头结点(即获取到同步状态的线程)的状态是否为PROPAGATE来获
                //取共享同步状态。
                //以上例子为个人理解,实际实现可能还有其他要求。
                else if (ws == 0 &&
                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            //确保head节点在此次释放过程中未被改变
            if (h == head)                   // loop if head changed
                break;
        }
}

查看doAcquireShared方法unparkSuccessor方法
此方法setHeadAndPropagate方法releaseShared方法被调用
说明:此方法共享式获取同步状态的核心方法,跟独占式获取同步状态相同之处在于,两者都是根据自己的等待状态(SIGNAL,表示后继节点需要唤醒)唤醒后继节点。不同之处在于,独占式获取同步状态在自己的等待状态为0时(表示后面没有节点需要唤醒)会在释放同步状态之后直接离开同步队列,而共享式获取同步状态会在释放之前将自己的等待状态变为PROPAGATE,以告诉后来的线程这个锁为可获取状态,后面的线程在尝试获取锁的时候可以根据这个状态来判断是否直接获取锁。需要注意的是,每次唤醒的仅仅是其后继节点,但若后继节点不是共享模式的话,就不会再去唤醒更后面的节点了。

响应中断

acquireSharedInterruptibly方法

public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
}

查看doAcquireSharedInterruptibly方法

acquireSharedInterruptibly方法

private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {//共享式获取同步状态
                    int r = tryAcquireShared(arg);//需重写,自行实现
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())//若阻塞(被挂起)时发生中断,那么被唤醒之后抛出InterruptedException异常
                    throw new InterruptedException();
            }
        } catch (Throwable t) {
            cancelAcquire(node);//发生异常取消获取同步状态
            throw t;
        }
}

此方法与独占式获取同步状态(响应中断)doAcquireInterruptibly方法中断处理逻辑一致。
查看doAcquireSharedInterruptibly方法shouldParkAfterFailedAcquire方法parkAndCheckInterrupt方法cancelAcquire方法
此方法acquireSharedInterruptibly方法被调用

共享式超时获取同步状态

doAcquireSharedNanos方法

private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;
        final Node node = addWaiter(Node.SHARED);//构造共享模式节点放入同步队列
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {//共享式获取同步状态
                    int r = tryAcquireShared(arg);//需重写,自行实现
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        return true;
                    }
                }
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L) {
                    cancelAcquire(node);
                    return false;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } catch (Throwable t) {
            cancelAcquire(node);
            throw t;
        }
}

此方法与独占式超时获取同步状态(doAcquireNanos方法)的超时处理逻辑一致,区别仅在与前者为共享式获取同步状态,后者为独占式获取同步状态。
查看addWaiter方法setHeadAndPropagate方法shouldParkAfterFailedAcquire方法parkAndCheckInterrupt方法cancelAcquire方法

总结

独占式获取同步状态的总结

返回顶部

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值