可重入锁 ReentrantLock的部分源码解析
ReentrantLock是 Java 中一个常用的锁实现,位于java.util.concurrent.locks包中。它提供了更灵活的锁机制,相比于synchronized关键字,ReentrantLock提供了更多高级功能,例如可重入锁、可定时、可中断的获取锁等。
基本结构
ReentrantLock 实现了 Lock 接口,主要依赖一个同步器 AbstractQueuedSynchronizer(AQS)来完成锁的获取与释放。其内部有两个子类,分别是 NonfairSync 和 FairSync,它们分别对应非公平锁和公平锁的实现。
内部方法
ReentrantLock 类的源码主要分为以下几个部分:
-
类声明和字段:
ReentrantLock类实现了Lock接口,并且是可序列化的。Sync是一个抽象静态内部类,继承自AbstractQueuedSynchronizer,用于实现锁的同步机制。NonfairSync和FairSync是Sync的两个子类,分别实现了非公平锁和公平锁的逻辑。
-
构造方法:
ReentrantLock():默认构造方法,默认创建一个非公平锁。ReentrantLock(boolean fair):带有公平性参数的构造方法,根据参数创建公平锁或非公平锁。
-
锁的获取和释放方法:
lock():获取锁,如果当前线程已经持有锁,则增加持有计数。lockInterruptibly():获取锁,支持中断。tryLock():尝试获取锁而不进行等待。直接使用 CAS 操作尝试更新状态tryLock(long timeout, TimeUnit unit):在指定时间内尝试获取锁,支持中断。unlock():释放锁,减少持有计数,如果计数为零则真正释放锁。
-
条件变量:
newCondition():返回一个与此锁关联的Condition实例ConditionObject,用于线程间的协调,条件等待
-
锁状态查询方法:
getHoldCount():查询当前线程持有锁的次数。isHeldByCurrentThread():查询当前线程是否持有锁。isLocked():查询锁是否被任何线程持有。isFair():查询锁是否是公平锁。getOwner():返回当前持有锁的线程。hasQueuedThreads():查询是否有线程在等待获取锁。hasQueuedThread(Thread thread):查询指定线程是否在等待获取锁。getQueueLength():返回等待获取锁的线程数的估计值。getQueuedThreads():返回等待获取锁的线程集合。hasWaiters(Condition condition):查询是否有线程在等待指定的条件。getWaitQueueLength(Condition condition):返回等待指定条件的线程数的估计值。getWaitingThreads(Condition condition):返回等待指定条件的线程集合。
-
内部类
Sync:nonfairTryAcquire(int acquires):非公平地尝试获取锁。tryRelease(int releases):尝试释放锁。isHeldExclusively():查询当前线程是否独占锁。newCondition():创建一个新的ConditionObject实例。getOwner():返回当前持有锁的线程。getHoldCount():返回当前线程持有锁的次数。isLocked():查询锁是否被任何线程持有。readObject(java.io.ObjectInputStream s):反序列化时重置锁的状态。
-
内部类
NonfairSync和FairSync:NonfairSync:实现非公平锁的tryAcquire方法。直接插入锁队列的最前面,容易导致“饥饿”现象。但性能更高,因为减少了很多竞争FairSync:实现公平锁的tryAcquire方法,确保锁的获取是公平的。按照请求锁的顺序来分配锁,能保证线程不会饥饿
-
其他方法:
toString():返回锁的状态信息。
-
AQS 的作用
AbstractQueuedSynchronizer是 ReentrantLock 实现的核心,它维护了一个 FIFO 队列,管理线程间的同步状态:- state: 同步状态。0 表示未锁定状态,1 或更高表示锁定状态。
- CLH 队列: 用于管理等待线程。
- condition queue: 用于管理在某个条件上等待的线程。
部分源码
Sync
//在ReentrantLock代码里,Sync其内部的抽象静态类,这个类继承了AbstractQueuedSynchronizer
//Sync 底下还有两个内部类,一个实现非公平,一个实现公平,都继承 Sync。所以说ReentrantLock既是公平锁也是非公平锁。很公平的给你选择
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
//非公平的实现,调用了该方法
//可以发现该方法内部是直接进行CAS的compareAndSetState(0, acquires)来尝试更改状态为锁定
//并没有去查看等待队列,也并没有查看是否有比当前线程等待时间更久的
@ReservedStackAccess
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) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
//持有锁的计数减少,当计数回到0时,表明当前线程不再持有该锁
@ReservedStackAccess
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;
}
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
// Methods relayed from outer class
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {
return getState() != 0;
}
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
公平与非公平
/**
* 如上所述,非公平锁是调用了Sync的nonfairTryAcquire()方法实现
* 非公平锁(NonfairSync) 的实现允许"插队",即后来的线程可以直接尝试获取锁,而不考虑等待队列中的其他线程。这种做法可以提高吞吐量但可能导致某些线程一直不能获取到锁
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
//公平锁:确保队列中等待时间最长的线程最先获得锁。在这种模式下,锁的获取会先检测队列是否为空,若不为空则排队。
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
//公平锁是会去判断等待队列,并且查看当前线程是不是等待时间最长的,然后再进行compareAndSetState来尝试改变状态
//如果队列中有等待线程,则当前线程不能插队
@ReservedStackAccess
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
/**
* hasQueuedPredecessors() 方法是公平锁机制的核心部分,这个方法的作用是检查当前线程是否有其他前驱线程
*(通常是通过检查等待队列中是否存在等待更长时间的线程,实现公平性):
实现逻辑:它检查同步队列中是否有其他线程在等待锁定,即判断是否有比当前线程更早进入队列的线程。
如果 hasQueuedPredecessors() 返回 false,则意味着当前线程可以在公平条件下获取锁,即它要么是队列中的头线程,要么队列是空的。
*/
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;
}
}
/**
可重入锁提供了两个构造函数
无参构造默认是创建非公平锁
*/
public ReentrantLock() {
sync = new NonfairSync();
}
//含参狗砸则通过是否创建公平锁的布尔值参数来创建对应的锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
···
···
/**
当我们实例化一个ReentrantLock对象后,lock()时直接调用acquire(1)来获取锁
acquire()是AbstractQueuedSynchronizer提供的方法,内部是调用tryAcquire(arg)尝试获取,如果失败则进行线程排队,如下
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
所以实例化的ReentrantLock若是公平的,则调用FairSync的tryAcquire()自定义实现;若是非公平的,则调用NonfairSync的自定义tryAcquire()实现
*/
public void lock() {
sync.acquire(1);
}
···
···
//释放锁
public void unlock() {
sync.release(1);
}
当然再往里挖,就到了实现的核心AbstractQueuedSynchronizer抽象类了,想把这个再挖清楚,暂时我做不太到···
Condition 条件等待
Condition 是用于协调线程间通信的一种机制,它依赖于一个 Lock 实现来支持更复杂的线程同步方案。ReentrantLock 提供了对 Condition 对象的支持,允许线程在特定条件下等待和被唤醒。
//在 ReentrantLock 内部,Condition 是通过它的内部类 ConditionObject 来实现的。这是 AbstractQueuedSynchronizer 的一个嵌套类,用于条件等待
final ConditionObject newCondition() {
return new ConditionObject();
}
···
···
public Condition newCondition() {
return sync.newCondition();
}
创建 Condition
在 ReentrantLock 中,创建一个 Condition 对象是通过调用 newCondition() 方法实现的。例如:
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
这会创建一个与该锁关联的 ConditionObject。
ConditionObject 工作原理
-
await() 方法
当一个线程调用
await()方法时,它将是以下流程:- 它必须持有锁,否则会抛出
IllegalMonitorStateException。 - 当前线程会释放锁,并将自己加入到条件队列中。
- 进入等待状态,直到收到信号 (
signal()或signalAll()) 或被中断。 - 线程被唤醒后,需要重新获取锁,线程能继续执行后续的代码。
- 它必须持有锁,否则会抛出
-
signal() 方法
signal()方法用于唤醒等待条件队列中的一个线程。流程如下:- 调用
signal()的线程必须持有锁,否则会抛出IllegalMonitorStateException。 - 唤醒队列中第一个等待的线程,使其从等待中恢复。
- 被唤醒的线程会从条件队列移动到同步队列,以便尝试获取锁。
- 调用
-
signalAll() 方法
类似于
signal(),但它会唤醒条件队列中所有的等待线程。
代码示例
一个简单的使用 ReentrantLock 和 Condition 的示例可能如下:
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void awaitCondition() throws InterruptedException {
lock.lock();
try {
while (/* condition not met */) {
condition.await();
}
// Do something once the condition is met
} finally {
lock.unlock();
}
}
public void signalCondition() {
lock.lock();
try {
// Update condition state
condition.signal();
} finally {
lock.unlock();
}
}
注意事项
- 使用
Condition之前,线程必须先获取相关的锁。 - 在
await()和signal()之间,条件的检查和状态的改变要在lock内保证同步。 signal()通常在修改共享状态并使得某些条件变为真的地方调用。
不同于synchronized,synchronized是实例对象 或者 类class这样的单一监视器锁,它们的等待和唤醒是由顶级父类Object提供的唤醒和等待方法notify(),notifyAll(),wait()。而ReentrantLock可以绑定多个Condition条件等待,由Condition提供更加灵活的等待和唤醒,并且可中断等待 等等操作
ReentrantLock lock = new ReentrantLock();
Condition conditionA = lock.newCondition();
Condition conditionB = lock.newCondition();
//在这个例子中,两个不同的条件(可能是某种资源的两种状态)使用了两个不同的 Condition 对象。每个条件的等待和通知操作都是独立的,而不需要共享同一个内置条件(即与该对象关联的单一监视器锁)
// 某个线程:
lock.lock();
try {
while (!someCondition()) {
conditionA.await();
}
// 处理逻辑...
} finally {
lock.unlock();
}
// 另一个线程:
lock.lock();
try {
while (!otherCondition()) {
conditionB.await();
}
// 处理逻辑...
} finally {
lock.unlock();
}
或者
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void waitForCondition() throws InterruptedException {
lock.lock();
try {
// 某种条件不满足时,线程等待
while (!conditionMet()) {
condition.await();
}
// 在条件满足后执行的逻辑
} finally {
lock.unlock();
}
}
public void signalCondition() {
lock.lock();
try {
// 更改条件,然后通知等待的线程
modifyConditions();
condition.signalAll(); // 可以使用 signal() 唤醒一个线程,或使用 signalAll() 唤醒所有等待线程
} finally {
lock.unlock();
}
}
private boolean conditionMet() {
// 逻辑检查条件是否满足
return true; // 示例值
}
private void modifyConditions() {
// 更改条件的实际操作
}


浙公网安备 33010602011771号