读锁
tryAcquireShared()
加锁失败则返回-1 成功则返回>0
tryAcquireShared(arg) < 0
加锁




1. 在获取读锁时,会尝试判断当前对象是否拥有了写锁(排它),如果已经拥有,则直接失败。
2. 如果没有写锁,就表示当前对象没有排他锁,则当前线程会尝试给对象加锁
3. 如果当前线程已经持有了该对象的读锁,那么直接将读锁数量加1
protected final int tryAcquireShared(int unused) {//这里主要是为了性能 缓存了第一次和最后一次加锁的信息Thread current = Thread.currentThread();int c = getState();//首先判断是否被上了写锁//exclusiveCount(c) != 0 标识上了写锁//但是还会继续判断为什么上了写锁还要继续判断-----》重入或者降级//然后再判断是否是重入如果这里是重入则一定是降级 如果不是重入则失败 读写需要互斥if (exclusiveCount(c) != 0 &&getExclusiveOwnerThread() != current)return -1;//如果上面代码没有返回,执行到这里,有两种情况标识1、没有人上写锁 2、重入降级int r = sharedCount(c);//得到r的上锁次数if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) {//r 是加锁之前的//r == 0 标识 这是第一次给这把锁加读锁 之前没有人加锁if (r == 0) {//如果是第一个线程第一次加锁(之前没有人加过锁),则把这个线程付给firstReader 局部变量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);}
加锁失败 阻塞
private void doAcquireShared(int arg) {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
//被唤醒时再去拿锁
int r = tryAcquireShared(arg);
if (r >= 0) {
//如果队列中自己的后面也是读锁,把它也唤醒
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//如果被唤醒,从这里开始
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}

