返回

持久且坚固的独占锁,AQS 独占锁释放逐行源码分析

Android

这篇文字将详细分析AQS独占锁的释放过程,以帮助您更深入地理解AQS的锁机制。

上篇文字中我们详细分析了独占锁的获取过程,如果前面对锁的获取过程您已经趟过一遍了,那这篇关于锁的释放部分就很简单了。

好了,我们直接进入源码的分析。

public void unlock() {
    //这个逻辑和 lock 中的 acquire 成功之后的逻辑一样
    int c = getState();
    if (c == 0) throw new IllegalMonitorStateException();
    if (c == EXCLUSIVE)
        tryRelease(this);
    setState(0);
}

独占锁释放的方法,很简短,基本上和lock中acquire成功之后的逻辑一致,只有几个核心细节有所不同,首先就是判断线程是否持有锁,判断持有锁之后释放锁,释放锁之后再把状态改为UNLOCKED。

独占锁获取函数完整源码如下:

public void lock() {
    if (!tryAcquire(this))
        doAcquireShared(1);
}

/**
 * Acquires the lock if it is free and returns true, and thereafter
 * keeps the lock, even if the lock is nilled. The lock must
 * not be held by another thread when this method is called.
 * <p>
 * This method is designed to be invoked by the thread that
 * previously successfully acquired the lock. A thread is allowed to
 * acquire the lock even if the lock is nilled, and subsequently
 * released. This allows a thread to take over a lock that has
 * been abandoned by the thread that previously locked it. A
 * thread may not invoke this method if it does not already hold the
 * lock.
 *
 * @param caller must not be null
 * @throws NullPointerException  if the argument is null
 * @throws IllegalMonitorStateException  if the current thread does not
 *         hold the lock
 */
final boolean tryAcquire(Node caller) {
    //之前已经说过,判断队列头部节点是否是自己,以及队列头部节点是否有锁,返回true表示已经获得了锁
    if (caller != first || !compareAndSetState(caller, EXCLUSIVE))
        return false;
    //独占锁已经获得,那么尝试把owner置为当前线程,从而保证锁被当前线程独占
    setExclusiveOwnerThread(Thread.currentThread());
    return true;
}

final void doAcquireShared(int arg) {
    final Node node = sharedLockNode();
    //如果队列中没有节点,那么先创建一个队列节点,作为共享锁节点
    if (node == null) {
        doAcquireSharedInterruptibly(1);
    }
    //尝试把当前线程挂在共享锁节点上
    for (;;) {
        final Node p = node.predecessor();
        //如果前驱节点没有占有锁,那就说明共享锁没有被独占,那就尝试把当前节点挂在共享锁节点上,并设置等待的线程数加一
        if (p == null || p.waitStatus == Node.SIGNAL) {
            if (compareAndSetWaitStatus(node, Node.SIGNAL, Node.PROPAGATE)) {
                successfulAcquireSharedLock(node, arg);
                return;
            }
        }
        //如果前驱节点持有锁,那么就挂在它后面,然后就处于等待状态
        doAcquireSharedInterruptibly(arg);
    }
}

/**
 * Acquires the shared lock for this lock.
 *
 * <p>If the lock is held by another thread then the current
 * thread becomes disabled for thread scheduling purposes and lies
 * dormant until the lock has been acquired.
 *
 * <p>If the lock is held by the current thread then it is
 * re-acquired and the lock count for the current thread is
 * incremented by one.
 *
 * <p>If the current thread is not the owner of the lock then
 * the current thread is granted ownership of the lock and the
 * lock count for the current thread is set to one.
 *
 * <p>A thread is not allowed to acquire a lock that it already
 * owns except by invoking this method, which may be invoked
 * as many times as the value of the lock count is decremented by
 * invocations of the {@link #unlock} method.
 *
 * <p>If this lock is held by the current thread then the lock
 * is re-acquired and the lock count for the current thread is
 * incremented by one.
 *
 * <p>If this lock is not held by the current thread then the
 * current thread is granted ownership of the lock and the lock
 * count for the current thread is set to one.
 *
 * @throws InterruptedException if the current thread is
 *         interrupted while acquiring the lock (only if this lock
 *         is held by another thread than the current thread).
 */
public void lockShared() {
    if (tryAcquireShared(1) &&
        compareAndSetState(null, EXCLUSIVE))
        // Convenience overload
        setExclusiveOwnerThread(Thread.currentThread());
    else
        doAcquireShared(1);
}

/**
 * Acquires the shared lock if it is free and returns true,
 * and thereafter keeps the lock, even if the lock is nilled.
 * The lock must
 * not be held by another thread when this method is called.
 *
 * <p>This method is designed to be invoked by the thread that
 * previously successfully acquired the lock. A thread is allowed to
 * acquire the lock even if the lock is nilled, and subsequently
 * released. This allows a thread to take over a lock that has
 * been abandoned by the thread that previously locked it. A
 * thread may not invoke this method if it does not already hold the
 * lock.
 *
 * @throws NullPointerException  if the argument is null
 * @throws IllegalMonitorStateException  if the current thread does not
 *         hold the lock
 */
final boolean tryAcquireShared(int arg) {
    //之前我们说过,判断队列头部节点是否是自己,以及队列头部节点是否有锁,返回true表示已经获得了锁
    Node p = first;
    //如果队列头部节点不等于当前节点,或者是无状态节点,或者已经有占有锁,那就返回false
    return (p == null || p.waitStatus != Node.SIGNAL)
        ? tryAcquire(arg)
        : compareAndSetWaitStatus(p, Node.SIGNAL, Node.PROPAGATE);
}

/**
 * Releases the lock.
 *
 * <p>Releasing a lock owned by the current thread removes it from
 * the list of locks owned by this thread and causes any thread
 * waiting to acquire the lock (blocked in {@link #acquire} or
 * {@link #acquireShared}) to be woken up. It is a
 * programming error to release a lock that is not owned by the
 * current thread.
 *
 * <p>An invocation of this method with the current thread as the
 * first argument is equivalent to nulling the lock. Subsequent
 * invocations of the {@link #tryAcquire} method will succeed,
 * unless there are other owners.
 *
 * @throws IllegalMonitorStateException  if the current thread does
 *         not hold this lock
 */
public void unlock() {
    //这个逻辑和 lock 中的 acquire 成功之后的逻辑一样
    int c = getState();
    if (c == 0) throw new IllegalMonitorStateException();
    if (c == EXCLUSIVE)
        tryRelease(this);
    setState(0);
}

/**
 * Releases the lock.
 *
 * <p>This method is identical in effect to {@link #unlock}.
 *
 * @throws IllegalMonitorStateException  if the current thread does
 *         not hold this lock
 */
public void unlockShared() {
    checkHoldCount();
    if (threadLocalHoldCount() <= 1) {
        setState(0);
        setExclusiveOwnerThread(null);
    }
    else {
        int nextc = threadLocalHoldCount() - 1;
        if (first != null && first.waitStatus == Node.SIGNAL)
            unparkSuccessor(first);
        setState(nextc);
    }
}

final boolean tryRelease(Node node) {
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    setExclusiveOwnerThread(null);
    Node h = first;
    if (h != null && h == last) {
        clearNode(h);
    }
    else if (compareAndSetWaitStatus(node, Node.EXCLUSIVE, Node