ReentrantReadWriteLock
外部类 Sync 简介:
后面看过 AQS 咱们都晓得,AQS 中应用一个 int 型变量来示意锁的持有数,然而对于 ReentrantReadWriteLock 来说,它是分读锁和写锁,那么如何示意这两种锁的持有数呢?读写锁中采纳的形式就是将 int 型一分为二,高 16 位,所有线程持有的读锁数,低 16 位用来示意写锁的持有个数;
读锁是一个共享锁,高 16 位示意的是所有线程总的持读锁数,那如何获取以后线程重入读锁数呢?这里天然引入了 ThreadLocal 来保留每个线程重入读锁的计数。
static final int SHARED_SHIFT = 16;// 用于计数出高 161 位的偏移值(读锁)static final int SHARED_UNIT = (1 << SHARED_SHIFT);//65536
// 最大持锁个数
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; // 用于计数出 state 的低 16 位的掩码
// 该办法获取 int 变量高 16 位,即读锁持有计数
static int sharedCount(int c) {return c >>> SHARED_SHIFT;}
// 该办法获取 int 变量低 16 位,即写锁持有计数
static int exclusiveCount(int c) {return c & EXCLUSIVE_MASK;}
// HoldCounter 变量用于存储每个线程 id 以及对应的读锁持有计数
static final class HoldCounter {
int count = 0;
// 应用线程 id 而不是线程援用,是为了避免残留
// 这里可能是思考到强援用,垃圾对象无奈回收,导致内存泄露
final long tid = getThreadId(Thread.currentThread());
}
// 以后线程持有的读锁计数,ThreadLocalHoldCounter 其实就是一个 ThreadLocal<HoldCounter>
private transient ThreadLocalHoldCounter readHolds;
// 上面三个变量是用的比拟多的变量,为了进步获取效率,就独自缓存了
// 保留上个申请读锁线程的 HoldCounter。private transient HoldCounter cachedHoldCounter;
// 保留第一个获取到读锁的线程
private transient Thread firstReader = null;
// 保留第一个获取到读锁的线程持有的读锁计数
private transient int firstReaderHoldCount;