返回
持久且坚固的独占锁,AQS 独占锁释放逐行源码分析
Android
2023-09-02 07:13:38
这篇文字将详细分析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