AQS源码解读(AbstractQueuedSynchronizer)

首先类看一下AQS的静态内部类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;
        /** 这个常量代表线程正在等待condition */
        static final int CONDITION = -2;
        /**
         * 这个常量代表下一个acquireShard(获取共享锁)要无条件传播?
         */
        static final int PROPAGATE = -3;

        /**
         * 这个变量代表等待变量,它的值只能取上面定义的几个常量CANCELLED ,SIGNAL,CONDITION ,PROPAGATE 
         */
        volatile int waitStatus;

        /**
         * 这个变量指向前一个节点,可以看出Node是双向链表中一个节点的数据类型
         */
        volatile Node prev;

        /**
         * 这个变量指向后一个节点
         */
        volatile Node next;

        /**
         * 线程,为了将线程放入队列中管理起来,用队列的节点Node包装了线程
         */
        volatile Thread thread;

        /**
         * 指下一个等待condition的node,不知道怎么等待condition 
         */
        Node nextWaiter;

        /**
         * 如果nextWaiter == SHARED就说明是共享节点 
         */
        final boolean isShared() {
            return nextWaiter == SHARED;
        }

        /**
         * 获取前一个节点Node
         */
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }

        Node() {    // 这个构造方法通常用来构造列表头结点或者共享节点
        }

        Node(Thread thread, Node mode) {     // 用于构造等待队列的节点
            this.nextWaiter = mode;
            this.thread = thread;
        }

        Node(Thread thread, int waitStatus) { // 用到condition的时候用
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

AQS的变量

    /**
     * 等待队列的头结点
     */
    private transient volatile Node head;

    /**
     * 等待队列的尾节点
     */
    private transient volatile Node tail;

    /**
     * AQS维护的状态值,表示当前线程获取锁的次数
     */
    private volatile int state;

    /**
     * 这是线程自旋的等待时间,单位是纳秒
     */
    static final long spinForTimeoutThreshold = 1000L;

AQS的变量很简单,就首尾节点和状态值,而它的成员方法就是对等待队列和状态值的操作。

AQS成员方法解读

compareAndSetState

protected final boolean compareAndSetState(int expect, int update) {
        // 这里用的是native方法,不做深入
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

这个方法的用CAS的方式修改state值,而state是volatile修饰的,因此在多线程的情况下也能够保证线程安全。

compareAndSetHead、compareAndSetTail


    private final boolean compareAndSetHead(Node update) {
        return unsafe.compareAndSwapObject(this, headOffset, null, update);
    }


    private final boolean compareAndSetTail(Node expect, Node update) {
        return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
    }

这两个方法也是用CAS线程安全的方式设置AQS的等待队列头尾节点

compareAndSetWaitStatus

private static final boolean compareAndSetWaitStatus(Node node,
                                                         int expect,
                                                         int update) {
        return unsafe.compareAndSwapInt(node, waitStatusOffset,
                                        expect, update);
    }

这个方法也是用CAS线程安全的方式设置节点的状态waitStatus

compareAndSetNext

        private static final boolean compareAndSetNext(Node node,
                                                   Node expect,
                                                   Node update) {
        return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
    }

用于设置Node的next成员变量

setHead

private void setHead(Node node) {
        head = node;
        // 为什么头节点中没有线程呢?
        node.thread = null;
        // 因为是头节点,所以前面不会有节点
        node.prev = null;
    }

将一个节点设置为队列的头节点

enq

private Node enq(final Node node) {
        for (;;) {
            Node t = tail;
            if (t == null) { // 如果队列为空,就将新节点作为队列唯一一个节点,头节点和尾节点都指向它
                if (compareAndSetHead(new Node()))
                    tail = head;
            } else { // 如果队列不为空,将新节点插入作为尾节点
                node.prev = t;
                if (compareAndSetTail(t, node)) {
                    t.next = node;
                    return t;
                }
            }
        }
    }

这个方法的作用就是向等待队列插入节点,注意这个方法如果插入不成功就会不断尝试直到成功为止

addWaiter

private Node addWaiter(Node mode) {
        // 将当前线程创建一个新节点
        Node node = new Node(Thread.currentThread(), mode);
        Node pred = tail;
        // 先试着插入一次,插入成功就返回插入的节点,不成功就用enq插到成功为止
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }

这个方法还是将节点插入到等待队列,比enq多出一步创建节点而已

unparkSuccessor

private void unparkSuccessor(Node node) {
        /*
         * 如果节点的状态为负数即SIGNAL,CONDITION ,PROPAGATE,就把状态清零
         */
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);

        /*
         * 找到该节点后面一个处于阻塞状态(SIGNAL,CONDITION ,PROPAGATE)的节点,将它包含的线程唤醒
         */
        Node s = node.next;
        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); // 唤醒线程
    }

该方法的作用就是唤醒当前节点后面一个被阻塞节点中的线程

doReleaseShared

private void doReleaseShared() {
        for (;;) {
            Node h = head;
            // 如果头节点的状态为,SIGNAL唤醒头节点后面的一个阻塞节点
            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)                   // 这里通过一个for循环来保证线程安全性
                break;
        }
    }

这个方法貌似用于释放共享锁,不明白为什么唤醒头节点后面的线程就可以释放共享锁?

setHeadAndPropagate

private void setHeadAndPropagate(Node node, int propagate) {
        Node h = head; // 保留前一个头节点
        setHead(node); // 设置新的节点为头节点
        /*
         * propagate 是tryAcquireShared返回的值,不知道表示什么,这里的逻辑还不明确
         * 
         */
        if (propagate > 0 || h == null || h.waitStatus < 0 ||
            (h = head) == null || h.waitStatus < 0) {
            Node s = node.next;
            if (s == null || s.isShared())
                doReleaseShared();
        }
    }

该方法的作用是:1、设置头节点。2、如果后继节点处于共享阻塞状态就释放共享锁?

cancelAcquire

/**
     private void cancelAcquire(Node node) {
        if (node == null)
            return;

        node.thread = null;

        // 从当前节点向前找,找到状态不为取消CANCELLED的节点pred
        Node pred = node.prev;
        while (pred.waitStatus > 0)
            node.prev = pred = pred.prev;

        // 保存pred节点的下个节点
        Node predNext = pred.next;

        // 将当前节点的状态设置为CANCELLED
        node.waitStatus = Node.CANCELLED;

        // 写了一大堆,要做的就是把当前节点到pred节点中间的所有节点从等待队列移除
        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.
            int ws;
            if (pred != head &&
                ((ws = pred.waitStatus) == Node.SIGNAL ||
                 (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
                pred.thread != null) {
                Node next = node.next;
                if (next != null && next.waitStatus <= 0)
                    compareAndSetNext(pred, predNext, next);
            } else {
                unparkSuccessor(node);
            }

            node.next = node; // 使得当前节点不可达,让GC
        }
    }

这个方法的作用就是移除等待队列中的节点

shouldParkAfterFailedAcquire

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            return true;
        if (ws > 0) {
            /*
             * 前一个节点已经取消,就跳过继续往前找
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

这个方法主要的目的是当该线程尝试获取锁失败后,判断该线程是否应该进入阻塞,如果前一个节点的状态为waitStatus就进入阻塞,如果不是就继续尝试获取锁。

parkAndCheckInterrupt

private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);
        return Thread.interrupted();

阻塞线程,并且判断线程是否中断

acquireQueued

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node); //如果成功获取锁,就将当前的节点设置为头节点。看来等待队列中的头节点都是获取到锁的线程的节点
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                // 获取失败就进入阻塞
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

这个方法表示等待队列中的节点会去尝试获取锁,获取到的成为头节点,获取失败的则线程继续被阻塞。

doAcquireInterruptibly

private void doAcquireInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

这个方法与acquireQueued很像,区别在于它获取不到会抛出异常

doAcquireNanos

private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout; // 超时的时间点
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

这个方法获取不到锁会等待nanosTimeout纳秒再去尝试获取,还是获取不到就返回,不会阻塞。

doAcquireShared

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);
                    // 获取成功就设置新的头结点
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                // 阻塞等待
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

共享模式获取锁的时候在等待队列中添加的节点都是一个单例Node.SHARED

doAcquireSharedInterruptibly

private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        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
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

中断模式的获取共享锁

doAcquireSharedNanos

private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
        throws InterruptedException {

        long lastTime = System.nanoTime();
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        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
                        failed = false;
                        return true;
                    }
                }
                if (nanosTimeout <= 0)
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                long now = System.nanoTime();
                nanosTimeout -= now - lastTime;
                lastTime = now;
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

超时模式的获取共享锁

acquire

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

这个方法的就是用来获取独占锁的,如果一次获取失败,那么久不断尝试获取直到获取成功。

acquireInterruptibly

public final void acquireInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (!tryAcquire(arg))
            doAcquireInterruptibly(arg);
    }

这个方法的就是用来响应中断地获取独占锁的,如果一次获取失败,那么久不断尝试获取直到获取成功或者遇到中断。

tryAcquireNanos

public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquire(arg) ||
            doAcquireNanos(arg, nanosTimeout);
    }

这个方法获取独占锁,直到获取成功或遇到中断,或时间到

release

public final boolean release(int arg) {
    // 尝试释放锁,释放成功的话唤醒后面阻塞的线程
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

这个方法用于释放锁

acquireShared

public final void acquireShared(int arg) {
        if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
    }

不可中断的方式获取共享锁

acquireSharedInterruptibly

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

响应中断的方式获取共享锁

tryAcquireSharedNanos

public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquireShared(arg) >= 0 ||

超时的方式获取共享锁

releaseShared

public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

释放共享锁

猜你喜欢

转载自blog.csdn.net/qqqq0199181/article/details/81132550