java进阶-7-D -多线程-Lock专题- ReentrantReadWriteLock
相比起ReentrantLock ,ReentrantReadWriteLock 更像是将2个ReentrantLock包装到了一起,一个ReentrantLock是独占锁-writeLock,另外一个是共享锁-readLock ,当然这个内部还有一些润滑剂:比如写锁可以降级成读锁,但是读锁无法升级成写锁...
1.ReentrantReadWriteLock 实现了那些接口?
1.主类实现了 ReadWriteLock接口 2.内部类实现了Lock接口
Lock接口在前面以及介绍过了,这里简单说一下ReadWriteLock : 就2个方法 readLock , writeLock
2.ReentrantReadWriteLock 理解入口 内部类 :Sync
读写锁时分开实现的,写锁时独占式锁,所以和前一节的ReentrantLock类似;
读锁:共享锁,在AQS中有对应的参数设置;
1. 读锁获取锁一顿解析------->
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
//要是有写锁占据 且当前线程并不是占据的那个线程,那就返回 -1 失败
//从这儿我们看出来 在写锁的内部可以获取读锁
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
//要是读锁不应该被block 且 读锁数量还没越界 且 CAS->读锁数量+1 成功 那就
int r = sharedCount(c);
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
//就 判断读锁数量 -0 当前线程获取到读锁,数量变为1
//要是当前线程以及获取读锁 ,数量+1
//当前线程要是没有缓存就加一份,要是有了那就 缓存.holdcount +1 表示新线程
//获取读锁
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
return 1;
}
return fullTryAcquireShared(current);
}
3.关于写锁的一顿分析
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c); // 写锁状态
if (c != 0) {
// 写 == 0 并且 c != 0 表示 读 != 0,即有读锁时获取不到写锁
// 或者 写 != 0 (有写锁)时但是非本线程,不可以重入
if (w == 0 || current != getExclusiveOwnerThread())
return false;
//能走到这儿说明 现在是写锁占据,并且当前时写锁重入来了
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
setState(c + acquires);
return true;
}
// writerShouldBlock() 公平锁 判断队列前面是否有等待,非公平锁 返回false
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
for (;;) {
int c = getState();
if (exclusiveCount(c) != 0) {
// 这里对应锁降级,若当前线程已持有写锁,则允许当前线程继续获取读锁,否则直接返回
if (getExclusiveOwnerThread() != current)
return -1;
} else if (readerShouldBlock()) {
// 如果读线程需要阻塞
// 当前线程是第一次获取读锁的线程
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
// 当前线程不是第一次获取读锁的线程
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();
if (rh.count == 0)
readHolds.remove();
}
}
if (rh.count == 0)
return -1;
}
}
// 如果读锁达到了最大值,抛出异常
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 同步状态修改成功
if (compareAndSetState(c, c + SHARED_UNIT)) {
// 下面的处理与tryAcquireShared(int)类似
if (sharedCount(c) == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
cachedHoldCounter = rh; // cache for release
}
return 1;
}
}
}
我看到一篇博客总结的挺到位的,这里连接一个地址:
https://blog.****.net/qq_38293564/article/details/80533821