ReentrantLock
是基于 AbstractQueuedSynchronizer
(AQS)实现的可重入锁,它允许一个线程多次获取锁,并提供了公平和非公平两种锁获取模式。接下来,我们在之前 AQS源码分析基础上,详细分析 ReentrantLock
的源码和各个方法的实现。
1. 构造函数
ReentrantLock
提供了两种构造方式:默认的非公平锁,以及指定是否使用公平锁的构造方法。
public class ReentrantLock implements Lock, java.io.Serializable {
private final Sync sync;
// 默认构造函数,使用非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
// 可选择公平锁或非公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
}
ReentrantLock
中的锁逻辑都由内部类 Sync
及其两个子类 FairSync
和 NonfairSync
来完成。
NonfairSync
:非公平锁,允许线程插队。FairSync
:公平锁,严格遵守先到先得原则。
2. Sync
内部类
Sync
继承自 AQS,所有锁的核心功能都在这个类中。Sync
抽象类定义了几个用于实现锁的基础方法,这些方法被 FairSync
和 NonfairSync
实现。
abstract static class Sync extends AbstractQueuedSynchronizer {
abstract void lock(); // 抽象的锁方法,由子类实现
// 判断锁是否被当前线程持有
final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
// 获取锁的重入次数
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
// 判断锁是否被持有
final boolean isLocked() {
return getState() != 0;
}
}
3. 非公平锁 NonfairSync
在非公平锁中,线程获取锁时不会关心排队情况,当前线程可以直接尝试获取锁,插队竞争锁资源。
static final class NonfairSync extends Sync {
final void lock() {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
} else {
acquire(1); // 调用AQS的acquire()方法
}
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(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) // 溢出保护
throw new Error("Maximum lock count exceeded");
setState(nextc); // 重入次数增加
return true;
}
return false;
}
}
-
lock()
:首先使用 CAS(compareAndSetState)尝试直接获取锁。如果当前state
为 0,表示锁未被持有,可以直接获取锁;如果锁已被持有,则调用acquire(1)
,进入 AQS 的队列等待机制。 -
tryAcquire(int)
:尝试获取锁。如果锁未被持有(state == 0
),则通过 CAS 操作尝试获取锁;如果当前线程已经持有锁,则增加重入次数。
4. 公平锁 FairSync
公平锁遵循严格的先到先得原则,线程会按照进入队列的顺序获取锁。
static final class FairSync extends Sync {
final void lock() {
acquire(1); // 直接调用AQS的acquire()
}
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;
}
}
lock()
:直接调用acquire(1)
,进入 AQS 的锁获取流程。tryAcquire(int)
:如果state == 0
(锁未被占用),则会调用hasQueuedPredecessors()
来判断当前线程是否是队列中的第一个。如果是第一个,才允许获取锁,确保公平性。
5. unlock()
unlock()
方法用来释放锁,释放锁时调用 AQS 的 release()
方法。
public void unlock() {
sync.release(1);
}
5.1 release(int arg)
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
- 调用
tryRelease(arg)
方法尝试释放锁。 - 如果释放成功(返回
true
),唤醒同步队列中的下一个等待线程。
5.2 tryRelease(int arg)
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;
}
tryRelease
方法会减少state
值,表示锁的重入次数减少。如果state
减为 0,表示当前线程完全释放了锁,并将持有锁的线程设置为null
。
6. tryLock()
tryLock()
是非阻塞的锁获取方法,直接尝试获取锁并返回结果。
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
- 非阻塞地调用
tryAcquire
方法尝试获取锁。
7. tryLock(long time, TimeUnit unit)
该方法允许在线程尝试获取锁时设置超时时间。如果在指定的时间内获取锁失败,则返回 false
。
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
tryAcquireNanos
是AQS
提供的限时等待锁的获取方法。
public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) || doAcquireNanos(arg, nanosTimeout);
}
- 首先尝试直接获取锁(调用
tryAcquire(arg)
),如果失败则进入doAcquireNanos(arg, nanosTimeout)
,进入同步队列等待,直到超时或被唤醒。
8. 条件变量 newCondition()
ReentrantLock
支持条件变量,通过 newCondition()
方法获取一个 ConditionObject
,允许线程在获取锁的情况下等待,直到其他线程发出通知信号。
public Condition newCondition() {
return sync.newCondition();
}
ConditionObject
是 AQS 的内部类,用于实现条件队列。线程调用 await()
方法进入等待队列,而调用 signal()
或 signalAll()
方法则会唤醒等待队列中的线程。
public class ConditionObject implements Condition, java.io.Serializable {
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
public final void signal() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
}
await()
:线程进入条件等待,释放锁并挂起,直到被唤醒。signal()
:唤醒条件队列中的一个线程。
9. getHoldCount()
与 isLocked()
getHoldCount()
:返回当前线程持有锁的重入次数。调用Sync
类的getHoldCount()
方法。
public int getHoldCount() {
return sync.getHoldCount();
}
isLocked()
:判断锁是否被占用。调用Sync
类的isLocked()
方法。
public boolean isLocked() {
return sync.isLocked();
}
总结
ReentrantLock
基于 AQS 实现,提供了可重入锁机制,同时支持公平锁和非公平锁。ReentrantLock
主要依赖于内部类 Sync
来实现锁的具体逻辑,其中:
- 非公平锁 允许线程插队,直接抢占锁资源;
- 公平锁 遵循先到先得,保证锁的获取顺序。
ReentrantLock
还提供了 tryLock()
方法用于非阻塞获取锁,newCondition()
方法提供条件变量支持,使得它可以处理复杂的并发场景。