Java 并发编程之 AQS ReentrantLock 公平锁源码解析
Java juc AQS About 1,782 words部分源码
java.util.concurrent.locks.ReentrantLock.FairSync
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
@ReservedStackAccess
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
java.util.concurrent.locks.AbstractQueuedSynchronizer#hasQueuedPredecessors
public final boolean hasQueuedPredecessors() {
Node h, s;
if ((h = head) != null) {
if ((s = h.next) == null || s.waitStatus > 0) {
s = null; // traverse in case of concurrent cancellation
for (Node p = tail; p != h && p != null; p = p.prev) {
if (p.waitStatus <= 0)
s = p;
}
}
if (s != null && s.thread != Thread.currentThread())
return true;
}
return false;
}
公平锁会在每次上锁前都会去检查一下CLH
队列的头节点,判断是否为空,且头节点中的thread
字段是否是当前线程。
头节点的thread
的字段初始化时为空,解锁时也会将出队列节点的thread
字段置空。
第一次lock
时,头节点还没初始化,所以为null
,直接上锁成功。
锁重入时,需判断s.thread != Thread.currentThread()
。
所以公平锁抢得锁的时机只有在一开始没有竞争的情况下,如果有竞争了,其他线程都会进入CLH
队列。
Views: 2,027 · Posted: 2021-10-05
————        END        ————
Give me a Star, Thanks:)
https://github.com/fendoudebb/LiteNote扫描下方二维码关注公众号和小程序↓↓↓
Loading...