1 概述
ReentrantLock是基于AQS实现的一款独占锁,有公平锁和非公平锁两种模式。
默认是使用的非公平锁:
public ReentrantLock() {
sync = new NonfairSync();
}
也可指定模式:
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
- 1
ReentrantLock
实现了Lock
接口; - 2
ReentrantLock
定义了内部类Sync继承AQS:abstract static class Sync extends AbstractQueuedSynchronizer{....}
; - 3
Sync
是一个抽象类,有两个实现类NonfairSync
/FairSync
,分别用来实现非公平锁/公平锁。
官方示例:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
2 实现
本文仅从ReentrantLock的lock/unlock
的实现,分析如何基于AQS实现一个独占锁。
根据AQS约定(可参考AQS源码分析及核心方法解析):
- 1 lock:实现
tryAcquire
,并在lock时调用acquire
; - 2 unlock:实现
tryRelease
,并在unlock时调用release
。
2 lock()
ReentrantLock.lock()
调用了Sync.lock()
,而Sync.lock()
是一个抽象方法,由子类实现。
所以NonfairSync
/FairSync
两个类中,必然使用了acquire
方法去获取锁,并实现了tryAcquire
方法。
2.1 NonfairSync
2.1.1 lock
- 1 调用
compareAndSetState
将state值由0置换为1,成功的话,说明当前没有其他线程持有锁,不去排队,直接持有。通过setExclusiveOwnerThread
将当前线程设置为独占锁持有者。 - 2 否则通过
acquire
去排队。
final void lock() {
if (compareAndSetState(0, 1)) // 如果当前state==0,则说明没有其他线程持有锁,CAS成功。
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
2.1.2 tryAcquire
NonfairSync.tryAcquire
直接调用的Sync.nonfairTryAcquire
。
nonfairTryAcquire
是非公平的tryAcquire
实现方式,不会通过AQS.hasQueuedPredecessors
来判断是有线程在排队。
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// state == 0,说明没有其他线程持有锁。
if (compareAndSetState(0, acquires)) {
// 将当前线程设置为`独占锁持有者`,tryAcqire成功。
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
/*
如果当前线程正是`独占锁持有者`,叠加state,实现`可重入`,tryAcqire成功。
也就是说AQS的同步列表中,有多个当前线程的节点。
*/
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
2.2 FairSync
2.2.1 lock
没有做compareAndSetState
尝试,直接将自己加入AQS的同步队列中。
final void lock() {
acquire(1);
}
2.2.2 tryAcquire
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) { // state == 0,说明没有其他线程持有锁。
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
/*
`!hasQueuedPredecessors()` 说明AQS的同步队列中,没有比自己更优先的线程在等待
*/
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
/*
如果当前线程正是`独占锁持有者`,叠加state,实现`可重入`,tryAcqire成功。
也就是说AQS的同步列表中,有多个当前线程的节点。
*/
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
FairSync.tryAcquire
比NonFairSync.tryAcquire
多了一个!hasQueuedPredecessors()
的判断,其他流程都是一样的。
3 unlock()
unlock操作,NonFairSync
/FairSync
中没有区分,直接在Sync中实现。
Sync
中的unlock
调用了AQS.release
,并实现了tryRelease
。
public void unlock() {
sync.release(1);
}
3.1 tryRelease
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
// 当前线程不是`独占锁持有者`,抛出异常。
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) { // c == 0 说明锁已经完全释放。
free = true;
// 将当前`独占锁持有者`置空。
setExclusiveOwnerThread(null);
}
// 更新state值
setState(c);
return free;
}
4 总结
NonFairSync
/FairSync
基本流程是一样的,不同的是:
- 1
NonFairSync
在lock时,会先尝试compareAndSetState(0, 1)
抢占锁,失败的话再进行acquire(1)
;FairSync
直接进行acquire(1)
排队。 - 2
FairSync
在tryAcquire
时,在判断compareAndSetState(0, acquires)
的同时,多进行了一个hasQueuedPredecessors()
的判断,用于判断同步队列中是否有比自己优先的线程。