构造函数
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
构造函数fair参数用来判断是否为公平加锁,同时函数中定义了两个对象分别为读写和写锁,在使用过程中我们都是通过调用readerLock 、writerLock 两个实例的lock方法进行加锁。
第一步读锁readerLock .lock()解析
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;//依然使用的是FairSync对象进行加锁,只不过封装了一层
}
public void lock() {
sync.acquireShared(1);//获取共享锁
}
public final void acquireShared(int arg) {//AQS的方法,采用模板方法的设计模式,通过子类实现tryAcquireShared达到加锁的目的
if (tryAcquireShared(arg) < 0)//加锁
doAcquireShared(arg);//存入同步队列
}
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current)//当写锁存在并且非重入直接返回获取锁失败
return -1;
int r = sharedCount(c);
if (!readerShouldBlock() &&
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
//判断是否应该阻塞,不应该就尝试加锁一次
if (r == 0) {//记录第一次读的线程和次数
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) {
firstReaderHoldCount++;//第一次读线程号加1
} else {//通过线程本地变量存放线程ID和线程数
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);//循环尝试
}
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方法中加锁成功逻辑一致
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;
}
}
}
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) {
//加锁成功,设置当前节点为head节点,并唤醒后续节点,来获取共享锁
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);//撤销节点
}
}
流程图:
写锁
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))//尝试获取锁,获取失败入队列(入队列和独占锁是一样的)
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 0) {//存在锁
if (w == 0 || current != getExclusiveOwnerThread())//写锁等于0或者线程非持有锁线程
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
setState(c + acquires);//锁重入,重入状态+1
return true;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))//锁是否应该阻塞,不应该阻塞CAS尝试加锁
return false;
setExclusiveOwnerThread(current);//加锁成功设置线程ID
return true;
}
流程图:
解锁
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();//读锁为0是执行
return true;
}
return false;
}
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {//线程为第一个持有锁线程
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)
firstReader = null;
else
firstReaderHoldCount--;
} else {
//线程本地变量减1
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
int count = rh.count;
if (count <= 1) {
readHolds.remove();
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
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;
}
}
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {//状态修改为0
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
unparkSuccessor(h);//释放队列阻塞线程
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
流程图
写锁解锁
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())//是否为锁持有线程
throw new IllegalMonitorStateException();
int nextc = getState() - releases;//重入次数减1
boolean free = exclusiveCount(nextc) == 0;
if (free)//写锁是否释放完毕
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
流程图