JUC 之 ReentrantLock 源码解析
前面我们学习了 AQS 的源码,了解了 AQS 的实现原理,为我们后面即将学习的 ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore 等奠定了扎实的基础。Java 中同步器的实现均离不开 AQS 的支持。那么下面我们就从 ReentrantLock 开始逐一进行讲解。
首先我们先来看看类的继承体系,通过源码我们发现 ReentrantLock 实现了 Lock 接口,通过内部类的方式实现AQS的功能。先来看下 Lock 接口信息,通过源码我们可以清晰看到 Lock 接口提供了哪些功能,提供了 获取锁、释放锁以及 Condition 条件的创建功能。
Lock 接口
public interface Lock {
// 获取锁,获取失败阻塞等待
void lock();
// 获取锁,获取失败阻塞等待,阻塞过程中可被中断唤醒
void lockInterruptibly() throws InterruptedException;
// 尝试获取锁,获取不到立即返回
boolean tryLock();
// 尝试获取锁,获取不到,等待 time 时间后还是获取不到则立即返回
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
// 释放锁
void unlock();
// 创建一个等待条件
Condition newCondition();
}
Sync 内部类
ReentrantLock 的锁实现就是借助该内部类实现的,ReentrantLock 实现了 公平锁与非公平锁,Sync 抽象类提供了,非公平锁的获取锁实现以及释放锁的实现(公平与非公平通用逻辑)。
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
abstract void lock(); // 抽象方法,有子类实现
// 非公平锁的实现
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();// 取到当先线程信息
int c = getState();// 获取当前 state 信息(AQS中的 state 变量)
if (c == 0) {// 此判断表明暂时没有现成持有锁,CAS 抢锁,CAS 成功设置线程信息
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {// 持有锁的线程是当前线程,表明锁重入,对 state 变量加 1
int nextc = c + acquires;
if (nextc < 0) // int 值溢出了
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
// 释放锁,逻辑很简单,还原 state 值即可
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
// 创建条件对象信息
final ConditionObject newCondition() {
return new ConditionObject();
}
...
}
FairSync 公平锁
继承自 Sync 抽象类,实现了 AQS 的 tryAcquire 方法
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
// AQS 中定义的模板函数
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() && // 检测竞争队列中是否有值,有,表示有线程正在等待获取锁,与非公平锁的唯一区别就在于此了,非公平锁不会判断队列中是否有值,直接抢,抢不到在进入队列阻塞等待
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
NonfairSync 非公平锁
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
// 获取锁实现
final void lock() {
// 不管有没有线程在等待,先抢,抢不到调用 acquire 方法进入 AQS 中
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
ReentrantLock 的实现依赖于 Sync 内部类,所有的实现均交由 Sync 来实现。ReentrantLock 本身并没有完成同步器的功能,只是提供了操作同步器的入口。