简介
ReentrantLock 用于控制资源的访问;
ReentrantLock是独占锁,且支持公平锁与非公平锁;
ReentrantLock实现Lock接口,实现加锁、解锁 接口规范;
内部类Sync继承AQS,实现了获取、释放资源逻辑
基本成员
- Sync
- FairSync
- NonFairSync
Sync
描述:
同步对象,ReentrantLock的内部类,继承AQS,实现独占锁对应方法:tryAcquire、tryRelease、isHeldExclusively;
是FairSync、NonFairSync的父类,定义了通用的tryRelease、isHeldExclusively方法
FairSync
描述:
公平的同步对象,需要初始化ReentrantLock时传入true:new ReentrantLock(true)。
NonFairSync
描述:
非公平的同步对象,初始化ReentrantLock时默认为非公平
核心方法
- tryAcquire
- nonfaireTryAcquire
- tryRelease
tryAcquire(公平锁获取资源方式)
/*
*将资源设置为0或可重入时返回true,否则返回false
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 判断当前状态是否为0,为0代表有资源,可以抢占
if (c == 0) {
// 判断前面是否还有等待节点,false证明没有,当前线程所在的节点就是第一个
if (!hasQueuedPredecessors() &&
// CAS设置状态,期望0,目标1
compareAndSetState(0, acquires)) {
// 将当前线程设为拥有资源的线程
setExclusiveOwnerThread(current);
return true;
}
}
// 不为0则判断是否可以重入:判断持有资源的线程是否与当前线程一致,一致的话+1,并且不需要再CAS设置状态
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
nonfaireTryAcquire(非公平锁获取资源方式)
/**
* 将资源设置为0或可重入时返回true,否则返回false;
* 与公平锁tryAcquire唯一不同是,当state为0时,没有hasQueuedPredecessors判断
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 这里直接进行CAS获取资源,没有判断是否有前一个节点
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;
}
tryRelease(公平/非公平锁通用释放逻辑)
// 如果state为0,则释放成功
protected final boolean tryRelease(int releases) {
// 计算最新state = AQS.state - 1
int c = getState() - releases;
// 当前线程必须与拥有资源的线程是同一个
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 如果最新state为0,说明资源可以成功被释放了,并且将拥有资源的线程设为null
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
// 最新state不为0,说明当前资源已被重入,无需释放资源
setState(c);
return free;
}
问题点
- 公平锁与非公平锁区别
ReentrantLock初始化:true代表公平、false:非公平,无参默认非公平;
lock: 非公平锁会直接先进行CAS设置state,失败后再调用AQS#acquire,公平锁直接调用acqurie(jdk11版本两者一致);
tryAcquire:公平锁会调用AQS#hasQueuedPredecessors,是第一个节点后再CAS, 非公平锁没有该判断;
# 公平锁lock
final void lock() {
acquire(1);
}
# 非公平锁lock
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
公平性通常会降低吞吐量,但会降低可变性并避免饥饿。