01-ReentrantReadWriteLock.ReadLock#lock
ReentrantReadWriteLock#readLock 来获取读写锁中的读锁,写锁的使用规则为:
ReentrantReadWriteLock.ReadLock#lock → AbstractQueuedSynchronizer#acquireShared
public final void acquireShared(int arg) {
/** 若可用的共享锁数量小于0,则阻塞当前尝试获取共享读锁的线程 */
if (tryAcquireShared(arg) < 0)
/** 将当前线程封装到 Node 中,并加入到 sync 队列队尾 */
doAcquireShared(arg);
}
/** 这段代码与分析 ReentantLock 时的 acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 效果类似 */
复制代码
→ ReentrantReadWriteLock.Sync#tryAcquireShared
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
/** 如果写锁不空闲,而且持互斥写锁的线程非当前线程,阻塞当前线程 */
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
/** 下面的情况为:a) 持写锁的线程数量为0,或 b) 持写锁的线程数量不为0,但持锁线程为当前线程 */
int r = sharedCount(c);
/** 公平锁和非公平锁在这里的实现不太一样:
* a) 公平锁:sync 中有其他线程正在等待,则返回 true(当前线程不能获共享读锁);
* 否则,返回 false(当前线程可以用 CAS 尝试获取共享读锁)
* b) 非公平锁:sync 中第一个线程等待获取互斥写锁,则返回 true(当前线程不能获得共享读锁);
* 否则,返回 false(当前线程可以用 CAS 尝试获取共享读锁)
*/
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
/** 到这里,当前线程其实已经能够获得共享读锁了,下面只是更新一些数据 */
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null ||
rh.tid != LockSupport.getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
return 1;
}
/** 完整的尝试获取共享读锁的方法,处理了上述所有情况,以及上述未处理的情况,例如重入 */
return fullTryAcquireShared(current);
}
复制代码
02-ReentrantReadWriteLock.ReadLock#unlock
ReentrantReadWriteLock.ReadLock#unlock → AbstractQueuedSynchronizer#releaseShared
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
/** 读锁、写锁都空闲时,尝试唤醒 writer */
doReleaseShared();
return true;
}
return false;
}
复制代码
→ ReentrantReadWriteLock.Sync#tryReleaseShared
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null ||
rh.tid != LockSupport.getThreadId(current))
rh = readHolds.get();
int count = rh.count;
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
/** 主要内容在这里,如果 state == 0,即读锁、写锁都空闲,则唤醒等待的 writer */
for (;;) {
int c = getState();
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc))
// Releasing the read lock has no effect on readers,
// but it may allow waiting writers to proceed if
// both read and write locks are now free.
return nextc == 0;
}
}
复制代码
03-ReentrantReadWriteLock.WriteLock#lock
ReentrantReadWriteLock#writeLock 来获取读写锁中的写锁,写锁的使用规则为:
若读锁、写锁均未被其他线程拥有,则当前线程立即获得写锁;
否则,当前线程阻塞。
若当前线程已获得写锁,则可以再次获得写锁(重入)。
若当前线程已获得读锁,则不可获得写锁,阻塞当前线程。
ReentrantReadWriteLock.WriteLock#lock → AbstractQueuedSynchronizer#acquire → ReentrantReadWriteLock.Sync#tryAcquire
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
/** ReentrantReadWriteLock 中,读锁与写锁的持锁线程数量在同一个值 getState() 中
* 低位部分表示持互斥写锁的线程数量
* 高位部分表示持共享读锁的线程数量
*/
int c = getState();
int w = exclusiveCount(c);
if (c != 0) { /** 说明读锁或写锁非空闲 */
// (Note: if c != 0 and w == 0 then shared count != 0)
if (w == 0 || current != getExclusiveOwnerThread())
/** w == 0,说明有人持有读锁,所以获取写锁失败 */
/** w != 0,说明有人持有读锁,若不是当前线程,则获取写锁失败 */
return false;
/** 有线程持有写锁,且持锁线程为当前线程,当前线程获锁成功(可重入) */
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
setState(c + acquires);
return true;
}
/** 读锁和写锁都空闲时,公平锁和非公平锁在这里的处理有点不同
* 公平锁,如果 sync 队列中有其他线程等待,则当前线程获取锁失败;
* 否则,只要 CAS 更新 state 成功则获取锁成功;
* 非公平锁,writerShouldBlock() 返回值一直为 false;
* 即不管 sync 队列,只要 CAS 更新 state 成功,则获取锁成功。
*/
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
复制代码
从上面的源码可以看到,出了某些地方需要考虑共享读锁的情况,其他部分与 ReentrantLock 这种互斥锁基本一致。
04-ReentrantReadWriteLock.WriteLock#unlock
写锁的 unlock 与 ReentrantLock 的 unlock 类似。ReentrantReadWriteLock.WriteLock#unlock → AbstractQueuedSynchronizer#release → ReentrantReadWriteLock.Sync#tryRelease
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
/** 持有写锁的线程才可释放写锁 */
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
/** 如果持有写锁的线程数量为0,则返回 true,
* AbstractQueuedSynchronizer#release 会唤醒 sync 队列中的 reader
*/
return free;
}
复制代码
历史文章推荐
Java Core 「12」ReentrantLock 再探析
Java Core 「11」AQS-AbstractQueuedSynchronizer
Java Core 「10」J.U.C 同步工具类 -2
Java Core 「9」J.U.C 同步工具类 -1
Java Core 「8」字节码增强技术
Java Core 「7」各种不同类型的锁
Java Core「6」反射与 SPI 机制
Java Core「5」自定义注解编程
Java Core「4」java.util.concurrent 包简介
评论