AQS同步队列之共享锁源码解析

AbstractQueuedSynchronizer作为java.util.concurrent包的基础,它提供了一套完整的同步编程框架,开发人员只需要实现其中几个简单的方法就能自由的使用诸如独占,共享,条件队列等多种同步模式。我们常用的比如ReentrantLock等基础类库都是基于AQS实现的,我们开发人员更应该了解它的实现原理,这样才能在使用过程中得心应手。
下面是获取同步锁的源码流程:(前提是了解下同步器流程以及CAS操作原理)

   /**
     * 通过一次调用来实现,共享锁获取模式,忽略中断。如果返回则代表成功,否则当前线程
     * 会在队列中自旋,直至成功返回。tryAcquireShared(arg) 返回的值如果<0则,获取锁失败
     * 需要进入队列,返回值>0则代表
     * 
     * @param arg the acquire argument.  This value is conveyed to
     *        {@link #tryAcquireShared} but is otherwise uninterpreted
     *        and can represent anything you like.
     */
    public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }
   /**
     * 尝试在共享模式下获取锁,该方法将会查询验证当前线程对象是否在共享模式中被获取,如果允
     * 许将会获取锁。继续执行
     * @返回值的几种状态:小于0获取失败;大于0则唤醒当前节点后所有可以唤醒的节点;等于0只能
     * 唤醒头节点之后的一个节点,也就是独占该锁;
     */
    protected int tryAcquireShared(int arg) {
        throw new UnsupportedOperationException();
    }
    /**
     * 不间断的获取锁。
     */
    private void doAcquireShared(int arg) {
        //新建共享节点,并加入队列尾部
        final Node node = addWaiter(Node.SHARED);
        //默认获取锁状态失败
        boolean failed = true;
        try {
            //等待线程被中断标记位
            boolean interrupted = false;
            for (;;) {
                //当前节点的前驱节点
                final Node p = node.predecessor();
                //如果是头节点(头节点代表是占用锁的节点)
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    //再次尝试获取锁,返回值大于0,也就是允许唤醒当前节点,
                    //以及后续节点
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                //前继节点非head节点,将前继节点状态设置为SIGNAL,通过park挂起node节点
                //的线程
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
   /**
     * 在共享模式下,设置队列的头,并检查后续节点是否在等待,(前提:参数propagate>0
     * 或当前节点waitStatus为PROPAGATE)态。
     * 自此传入的第一个node参数为新建的,获取共享锁的线程节点。
     */
    private void setHeadAndPropagate(Node node, int propagate) {
        //纪录老得头节点
        Node h = head; // Record old head for check below
        setHead(node);
        /**
         * 调用发方指示传播,尝试传递下个队列节点:
         * 头节点后面的节点需要被唤醒(waitStatus<0)
         * propagate > 0 表示调用方指明了后继节点需要被唤
         * 
         */
        if (propagate > 0 || h == null || h.waitStatus < 0 ||
            (h = head) == null || h.waitStatus < 0) {
            Node s = node.next;
            //如果当前节点的后继节点是共享类型或者没有后继节点,则进行唤醒
            if (s == null || s.isShared())
                //如果head节点状态为SIGNAL,唤醒head节点线程,重置head.waitStatus->0
                //head节点状态为0(第一次添加时是0),设置head.waitStatus设置为
                //Node.PROPAGATE表示状态需要向后继节点传播
                doReleaseShared();
        }
    }
  /**
     * 唤醒操作
     */
    private void doReleaseShared() {
        for (;;) {
            //纪录此时的头节点地址
            Node h = head;
            //当前头不为空,并且不是最后元素
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                //满足唤醒的条件
                if (ws == Node.SIGNAL) {
                    //设置当前节点的状态为0
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            //如果设置失败,重新循环
                     //上述成功设置为0后,进行唤醒,如果头节点的下个节点获取成功
                     //头节点就不会变换,继续执行,不回执行到 if (h == head)     
                    unparkSuccessor(h);
                }
                //(如果本身头节点的waitStatus是出于重置状态(waitStatus==0)的,将其
                //设置为“传播”状态。
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }
 /**
     * 继续唤醒后续节点,如果存在。
     */
    private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);

        Node s = node.next;
        //晒除前置节点为空,或者状态为"cancle"的节点,保证前驱节点的有效性。
        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);
    }

猜你喜欢

转载自blog.csdn.net/qq_36866808/article/details/82182911