ReentrantReadWriteLock之读锁加锁失败后流程
在fullTryAcquireShared方法前面做的操作,是第一遍尝试获取锁资源,获取失败了并不会退出,而是执行fullTryAcquireShared方法,此方法会再次尝试获取锁资源
final int fullTryAcquireShared(Thread current) {
HoldCounter rh = null;
for (;;) {
// 获取state值
int c = getState();
// 判断state值的低16位是否不为0
if (exclusiveCount(c) != 0) {
// 有线程持有写锁
if (getExclusiveOwnerThread() != current)
// 不是当前线程持有写锁
return -1;
// 判断是否可以竞争锁资源
} else if (readerShouldBlock()) {
// 可以竞争锁资源
// 无论公平锁还是非公平锁,只要进来,就代表要放到AQS链表中
// 处理ThreadLocal的内存泄漏问题
if (firstReader == current) {
// 当前线程是第一个拿到读锁的,不用处理
} else {
// 第一次进来肯定是null
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
// 当前线程不是最后一个拿到读锁的线程
// 获取当前线程的重入锁信息
// 调用get方法,如果此线程是第一次来获取读锁
// ThreadLocalMap必定没有数据
// 当ThreadLocalMap中没有数据时,get方法中会调用initialValue方法
// ThreadLocalHoldCounter对initialValue方法进行了重写
// 返回一个新的HoldCounter对象
// 并且将这个对象放到ThreadLocalMap中
rh = readHolds.get();
if (rh.count == 0)
// 当前线程没有拿到过读锁资源,是即将最后一个拿到锁资源的线程
// 其重入信息会存到cacheHoldCounter中
// 但是前面的get方法在其ThreadLocalMap中存入了HoldCounter对象
// 所以需要删除,避免ThreadLocal导致内存泄漏
readHolds.remove();
}
}
if (rh.count == 0)
// 进入这里说明当前线程是第一次来竞争读锁
// 但是if判断语句的readerShouldBlock方法能够返回true
// 说明现在第一次来竞争读锁的线程不能获取锁,直接退出方法,返回-1
return -1;
}
}
// 对于公平锁来说,到这里说明同步队列中没有节点
// 对于非公平锁来说,到这里说明同步队列中没有写线程节点
// 或者是当前线程来执行重入锁流程
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {
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;
}
return 1;
}
}
}