推荐答案
ReentrantLock 的底层实现基于 AbstractQueuedSynchronizer(AQS)。AQS 是一个用于构建锁和同步器的框架,它通过一个 FIFO 队列来管理线程的阻塞和唤醒。ReentrantLock 通过继承 AQS 并实现其抽象方法来实现可重入锁的功能。
本题详细解读
AQS 的核心思想
AQS 的核心思想是通过一个 volatile 的 int 类型的 state 变量来表示同步状态。state 的值可以表示锁的状态,比如 0 表示锁未被占用,1 表示锁被占用。AQS 还维护了一个 FIFO 队列,用于管理等待获取锁的线程。
ReentrantLock 的实现
ReentrantLock 通过继承 AQS 并实现其 tryAcquire 和 tryRelease 方法来实现锁的获取和释放。
1. 获取锁
当线程尝试获取锁时,ReentrantLock 会调用 AQS 的 acquire 方法,该方法会调用 tryAcquire 方法来尝试获取锁。
// www.javascriptcn.com code example
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}- 如果
state为 0,表示锁未被占用,当前线程通过 CAS 操作将state设置为 1,并将当前线程设置为独占锁的持有者。 - 如果
state不为 0,且当前线程已经是锁的持有者,则通过增加state的值来实现可重入。
2. 释放锁
当线程释放锁时,ReentrantLock 会调用 AQS 的 release 方法,该方法会调用 tryRelease 方法来释放锁。
// www.javascriptcn.com code example
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;
}- 如果
state减到 0,表示锁已经完全释放,当前线程不再是锁的持有者。 - 如果
state不为 0,表示锁仍然被持有,当前线程仍然是锁的持有者。
公平锁与非公平锁
ReentrantLock 支持公平锁和非公平锁两种模式。公平锁会按照线程请求锁的顺序来分配锁,而非公平锁则允许插队。
- 公平锁:在
tryAcquire方法中,会先检查是否有其他线程在等待获取锁,如果有,则当前线程不会尝试获取锁。 - 非公平锁:在
tryAcquire方法中,当前线程会直接尝试获取锁,而不考虑是否有其他线程在等待。
总结
ReentrantLock 的底层实现基于 AQS,通过 state 变量和 FIFO 队列来管理锁的状态和线程的阻塞与唤醒。ReentrantLock 支持可重入、公平锁和非公平锁等特性,是一个功能强大的同步工具。