ReentrantLock 是如何实现可重入性的?

ReentrantLock实现可重入性的关键在于其内部维护了一个同步状态(state)计数器,该计数器用于记录当前线程获取锁的次数。以下是ReentrantLock实现可重入性的详细解释:

一、同步状态计数器

ReentrantLock内部有一个名为sync的同步器对象,它继承自AbstractQueuedSynchronizer(AQS)。AQS是Java并发包中提供的一个用于构建锁和其他同步组件的框架。在AQS中,有一个名为state的字段,它是一个整数,用于表示同步状态。

在ReentrantLock中,state字段被用作计数器,用于记录当前线程获取锁的次数。当一个线程首次获取锁时,state被初始化为1,表示该线程已经获取了一次锁。如果同一个线程再次请求锁(即重入),state会递增,以记录该线程获取锁的次数。当线程释放锁时,state会递减,直到state降为0时,锁才被完全释放,此时其他线程才能获取该锁。

二、可重入性的实现原理

  1. 获取锁

    • 当一个线程尝试获取锁时,ReentrantLock会调用其内部的sync对象的nonfairTryAcquire或tryAcquire方法(取决于锁的类型,非公平锁或公平锁)。
    • 在这些方法内部,会首先检查state是否为0,即锁是否未被任何线程持有。如果是,则尝试通过CAS操作将state设置为1,并将当前线程设置为锁的持有者。如果CAS操作成功,则表示该线程成功获取了锁。
    • 如果state不为0,即锁已被其他线程持有,则会检查当前尝试获取锁的线程是否是当前持有锁的线程。如果是,说明发生了重入,此时会将state递增,并返回true表示获取锁成功。
  2. 释放锁

    • 当一个线程释放锁时,ReentrantLock会调用其内部的sync对象的tryRelease方法。
    • 在该方法内部,会首先检查当前线程是否是锁的持有者。如果不是,则抛出异常。
    • 如果是锁的持有者,则会将state递减,并检查state是否已降为0。如果是,表示锁已被完全释放,此时会将持有锁的线程设置为null,以便其他线程可以获取锁。

三、示例代码

以下是一个简单的Java代码示例,演示了ReentrantLock的可重入性:


import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockExample {
    private final ReentrantLock lock = new ReentrantLock();
    private int count = 0;

    public void increment() {
        lock.lock(); // 获取锁
        try {
            count++;
            System.out.println(Thread.currentThread().getName() + " - count: " + count);
            increment(); // 递归调用,测试ReentrantLock的可重入性
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    public static void main(String[] args) {
        ReentrantLockExample example = new ReentrantLockExample();
        
        // 创建并启动线程
        Thread thread1 = new Thread(example::increment, "Thread-1");
        thread1.start();
    }
}


综上所述,ReentrantLock通过内部维护一个同步状态计数器(state)来实现可重入性。当一个线程多次获取锁时,计数器会递增;当线程释放锁时,计数器会递减。直到计数器降为0时,锁才被完全释放。这种机制使得同一个线程可以多次获取同一个锁而不会导致死锁。在这个示例中,我们创建了一个ReentrantLock对象来保护共享资源count,并在increment()方法中获取锁。然后,我们递归调用increment()方法来测试ReentrantLock的可重入性。由于ReentrantLock是可重入的,因此同一个线程可以多次获取同一个锁而不会导致死锁。运行程序后,你会看到线程Thread-1能够不断地递归调用increment()方法,并正确地增加count的值。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值