AbstractQueuedSynchronizer抽象类源码分析

上面几章节介绍了读写锁和Sync抽象类,这节介绍AQS如何控制同步的

1.首先看一下类的定义

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable

官方对类的描述为:提供了一个框架实现阻塞锁,依赖于同步器(信号量、事件等)以及FIFO等待队列。该类为大多数同步器提供了一个有用的基础。

2.变量

    /**
     * Head of the wait queue, lazily initialized.  Except for
     * initialization, it is modified only via method setHead.  Note:
     * If head exists, its waitStatus is guaranteed not to be
     * CANCELLED.
     */
    private transient volatile Node head;//等待队列的头

    /**
     * Tail of the wait queue, lazily initialized.  Modified only via
     * method enq to add new wait node.
     */
    private transient volatile Node tail;//等待队列的尾

    /**
     * The synchronization state.
     */
    private volatile int state;//同步状态,锁个数

3.看一下Node节点的内容

static final class Node {
        /** 标记节点在共享模式中等待 */
        static final Node SHARED = new Node();
        /** 标记节点在独占模式中等待 */
        static final Node EXCLUSIVE = null;

        /** 等待状态,线程被取消 */
        static final int CANCELLED =  1;
        /** 等待状态,通知。当前线程的后继线程被阻塞或者即将被阻塞,当前线程释放锁或者取消后需要唤醒后继线程。这个状态一般都是后继线程来设置前驱节点的。 */
        static final int SIGNAL    = -1;
        /** 等待状态的枚举,表示线程正在等待 */
        static final int CONDITION = -2;
        /**
         * 等待状态的枚举值,表示下一个acquireShared应该无条件的传播,用于将唤醒后继线程传递下去,这个状态的引入是为了完善和增强共享锁的唤醒机制。在一个节点成为头节点之前,是不会跃迁为此状态的
         */
        static final int PROPAGATE = -3;

        /**
         * 等待状态
         */
        volatile int waitStatus;

        /**
         * 前一个节点
         */
        volatile Node prev;

        /**
         * 下一个节点
         */
        volatile Node next;

        /**
         * 线程
         */
        volatile Thread thread;

        /**
         * 下一个等待者
         */
        Node nextWaiter;

        /**
         * 是否处于共享模式
         */
        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        /**
         * 返回前一个节点,如果为空,则抛空指针异常
         *
         * @return the predecessor of this node
         */
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    // Used to establish initial head or SHARED marker
        }

        Node(Thread thread, Node mode) {     // Used by addWaiter
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // Used by Condition
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

4.acquireShared,获取读锁时用到

    public final void acquireShared(int arg) {//在共享模式中获取锁
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }

tryAcquireShared方法见Sync的实现,如果返回<0,说明获取锁失败,会调用doAcquireShared方法

    private void doAcquireShared(int arg) {
        final Node node = addWaiter(Node.SHARED);//等待队列中增加一个waiter
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {//获取锁成功
                        setHeadAndPropagate(node, r);//设置head节点且唤醒下一个线程或者传播状态
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())//获取失败,则检查并更新状态
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);//取消获取锁
        }
    }
    private void setHeadAndPropagate(Node node, int propagate) {
        Node h = head; // Record old head for check below
        setHead(node);//设置head
        /*
         * 唤醒队列中的下一个节点
         */
        if (propagate > 0 || h == null || h.waitStatus < 0 ||
            (h = head) == null || h.waitStatus < 0) {
            Node s = node.next;
            if (s == null || s.isShared())
                doReleaseShared();
        }
    }
    private void doReleaseShared() {
        /*
         * 
         */
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {//存在后续线程
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);//唤醒
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }

5.tryReadLock

        final boolean tryReadLock() {
            Thread current = Thread.currentThread();
            for (;;) {
                int c = getState();
                if (exclusiveCount(c) != 0 &&
                    getExclusiveOwnerThread() != current)
                    return false;//如果其他线程拥有写锁,则返回false
                int r = sharedCount(c);
                if (r == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");//如果读锁的个数超过最大,则报异常
                if (compareAndSetState(c, c + SHARED_UNIT)) {//如果设置状态成功
                    if (r == 0) {//如果读锁为0,设置第一个获取到读锁的线程
                        firstReader = current;
                        firstReaderHoldCount = 1;
                    } else if (firstReader == current) {//同一个线程,则读锁的个数加1
                        firstReaderHoldCount++;
                    } else {
                        HoldCounter rh = cachedHoldCounter;
                        if (rh == null || rh.tid != getThreadId(current))
                            cachedHoldCounter = rh = readHolds.get();//从threadLocal中获取锁个数
                        else if (rh.count == 0)
                            readHolds.set(rh);
                        rh.count++;
                    }
                    return true;
                }
            }
        }

总结一下AQS实现的大致思路:

AQS内部维护了一个队列管理锁。

线程会首先尝试获取锁,如果获取失败,则将当前线程以及等待状态包装成Node节点增加到等待队列中。

接着不断尝试获取锁,如果失败,则阻塞自己,直到被唤醒。

当持有锁的线程释放锁时,会唤醒队列中的后续线程。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章