[Java并发]AQS的可重入性
在Java中,AQS(AbstractQueuedSynchronizer,抽象队列同步器)通过设计一个独占和共享的同步机制,提供了可重入锁的实现。AQS 的可重入性主要依赖于它对线程状态的跟踪。具体来说,可重入性是指同一个线程在获得锁之后可以多次进入(加锁多次),而不引发死锁。这是通过一个“重入计数器”来实现的。
下面是AQS实现可重入性的核心机制:
1. 线程持有状态(state)#
AQS 使用一个 state
变量来表示锁的持有状态。在独占锁(如 ReentrantLock
)的情况下,state
变量记录锁被持有的次数。AQS 的设计允许同一个线程多次获取锁,每次获取锁时,state
变量会递增,而每次释放锁时,state
变量会递减,直到 state
变为 0 时,锁才会真正释放。
2. 当前持有锁的线程#
AQS 通过内部的一个线程引用 exclusiveOwnerThread
来跟踪当前持有锁的线程。当一个线程尝试获取锁时,AQS 会检查当前线程是否已经持有锁(即 exclusiveOwnerThread == currentThread
)。如果是同一个线程,则允许该线程再次获取锁,表示“可重入”。
3. 可重入的判断过程#
- 当一个线程第一次获取锁时,AQS 会将
exclusiveOwnerThread
设置为该线程,并将state
从 0 设置为 1。 - 如果同一线程再次尝试获取锁,AQS 看到
exclusiveOwnerThread
已经是当前线程,于是允许锁的重入,并将state
递增。 - 当线程释放锁时,AQS 会减少
state
的值。只有当state
减为 0 时,AQS 才会将exclusiveOwnerThread
置为 null,表示锁已完全释放。
4. 代码示例#
以 ReentrantLock
为例,ReentrantLock
是基于 AQS 实现的可重入锁:
class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();
public void performTask() {
lock.lock(); // 第一次加锁
try {
// 执行任务
anotherMethod(); // 同一线程可以再次加锁
} finally {
lock.unlock(); // 第一次解锁
}
}
public void anotherMethod() {
lock.lock(); // 第二次加锁
try {
// 执行其他任务
} finally {
lock.unlock(); // 第二次解锁
}
}
}
在这个例子中,performTask
和 anotherMethod
都会加锁,而由于是同一线程,所以 lock
会被允许多次加锁。
5. 锁的释放#
当线程多次加锁时,每次加锁都对应一次释放。只有当释放次数与加锁次数相等时,锁才会真正释放,允许其他线程获取。
总结#
AQS 的可重入性主要是通过 state
变量和 exclusiveOwnerThread
来实现的。它通过跟踪线程加锁的次数以及锁的当前拥有者,确保同一个线程可以多次进入锁区域,而不会导致死锁。这是 Java 中许多同步类(如 ReentrantLock
)的基础。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?