protectedfinalbooleantryAcquire(int acquires) {
/*
* Walkthrough:
* 1. If read count nonzero or write count nonzero
* and owner is a different thread, fail.
* 2. If count would saturate, fail. (This can only
* happen if count is already nonzero.)
* 3. Otherwise, this thread is eligible for lock if
* it is either a reentrant acquire or
* queue policy allows it. If so, update state
* and set owner.
*/Threadcurrent= Thread.currentThread();
intc= getState();
// 获取独占锁重入次数intw= exclusiveCount(c);
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)if (w == 0 || current != getExclusiveOwnerThread())
// 独占锁重入次数为 0,表示当前正在使用共享锁 || 正在使用独占锁,但是被其它线程锁了returnfalse;
if (w + exclusiveCount(acquires) > MAX_COUNT)
thrownewError("Maximum lock count exceeded");
// Reentrant acquire
setState(c + acquires);
returntrue;
}
// writerShouldBlock: 用于公平锁和非公平锁,当使用非公平锁时,该值永远为 false;使用公平锁时,当等待队列至少有两个节点时返回 trueif (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
returnfalse;
setExclusiveOwnerThread(current);
returntrue;
}
java
tryAcquireShared
protectedfinalinttryAcquireShared(int unused) {
/*
* Walkthrough:
* 1. If write lock held by another thread, fail.
* 2. Otherwise, this thread is eligible for
* lock wrt state, so ask if it should block
* because of queue policy. If not, try
* to grant by CASing state and updating count.
* Note that step does not check for reentrant
* acquires, which is postponed to full version
* to avoid having to check hold count in
* the more typical non-reentrant case.
* 3. If step 2 fails either because thread
* apparently not eligible or CAS fails or count
* saturated, chain to version with full retry loop.
*/Threadcurrent= Thread.currentThread();
intc= getState();
// 确保处于非独占模式或者当前线程获取了独占锁if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
intr= sharedCount(c);
if (!readerShouldBlock() &&
r < MAX_COUNT &&
// SHARED_UNIT 可以理解为 1,相当于共享锁重入了一次
compareAndSetState(c, c + SHARED_UNIT)) {
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} elseif (firstReader == current) {
firstReaderHoldCount++;
} else {
HoldCounterrh= cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
elseif (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
return1;
}
return fullTryAcquireShared(current);
}
staticfinalclassHoldCounter {
int count; // initially 0// Use id, not reference, to avoid garbage retentionfinallongtid= LockSupport.getThreadId(Thread.currentThread());
}
java
值得注意的是,当一个线程持有写锁时,它也可以尝试获取读锁,并且写锁不会被释放。在线程获取读锁后,由于 state 是整体的状态,无法表示单个线程重入了多少次,所以在后面还需要单独记录一个线程重入了多少次。
这里可以发现,当线程是第一个获取读锁时,它会将 firstReader 指向当前线程(这里不会有并发问题,r 为 0 就表示这个线程是第一个获取读锁的,因为 CAS 设置了 state,所以不可能出现两个 r 为 0 的情况)。后面来的线程,则将其存在了 ThreadLocal 中。