[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(); // 第二次解锁
        }
    }
}

在这个例子中,performTaskanotherMethod 都会加锁,而由于是同一线程,所以 lock 会被允许多次加锁。

5. 锁的释放#

当线程多次加锁时,每次加锁都对应一次释放。只有当释放次数与加锁次数相等时,锁才会真正释放,允许其他线程获取。

总结#

AQS 的可重入性主要是通过 state 变量和 exclusiveOwnerThread 来实现的。它通过跟踪线程加锁的次数以及锁的当前拥有者,确保同一个线程可以多次进入锁区域,而不会导致死锁。这是 Java 中许多同步类(如 ReentrantLock)的基础。

作者:Esofar

出处:https://www.cnblogs.com/DCFV/p/18446129

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   Duancf  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示