fair写锁的加锁源码解析
在上两篇中,我们仔细分析了nofair模式下的读锁的加锁与释放,这里再简单看一下fair模式下的写锁的加锁与释放
还是从加锁入手
ReadWriteLock lock = new ReentrantReadWriteLock(true);
Lock writeLock = lock.writeLock();
writeLock.lock();
//加锁
public void lock() {
sync.acquire(1);
}
public final void acquire(int arg) {
//1、尝试加锁
if (!tryAcquire(arg) &&
//2、加锁失败的话,将其添加到队列中
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
还是熟悉的配方,还是熟悉的味道
1、尝试加锁
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())
//直接返回false
return false;
//存在写锁 并且就是本线程 判断锁数量是否会超过最大的限制
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// 重入,再次获得锁 返回true
setState(c + acquires);
return true;
}
//不存在锁
//队列中下一个结点不是本线程的结点 则返回true 也就是 应该阻塞
//如果返回false,也就是下一次唤醒的就是本线程,那么尝试获取锁。
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
//获取锁成功,设置独占锁的线程为本线程
setExclusiveOwnerThread(current);
return true;
}
2、加锁失败,将其添加到队列中
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
//获取前置结点
final Node p = node.predecessor();
//前置结点是头节点
//再次尝试获取独占锁 也就是再走一遍步骤1
if (p == head && tryAcquire(arg)) {
//加锁成功 设置为头节点
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//以下与读锁的加锁原理的源码分析一致
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
至此,独占锁加锁源码分析完毕 。 感觉跟读锁加锁原理几乎一模一样 除了小细节,读锁可以有多个线程去持有,写锁只能一个线程去持有 其他基本一模一样的