掘金 后端 ( ) • 2024-05-06 14:15

在Java中,ReentrantLock 是实现再入锁(Reentrant Lock)的一个类,它属于 java.util.concurrent.locks 包。下面详细介绍 ReentrantLock 的原理,逻辑步骤,以及提供示例代码。

ReentrantLock 原理

  1. 线程安全性:ReentrantLock 提供了线程安全的锁定机制。

  2. 可重入性:与 synchronized 不同,ReentrantLock 明确地暴露了其可重入性质。如果当前线程已经持有锁,那么该线程可以再次获取锁而不会被阻塞。

  3. 公平性选择:ReentrantLock 允许你选择锁的公平性。公平性指的是锁的获取顺序按照请求的顺序进行。

  4. 尝试非阻塞获取:ReentrantLock 提供了尝试获取锁的方法,如果锁不可用,调用者可以不阻塞地继续执行。

  5. 超时获取:ReentrantLock 还提供了带超时的获取锁的方法,如果超过指定时间还不能获取到锁,将返回。

ReentrantLock 逻辑步骤

  1. 创建锁:首先,你需要创建一个 ReentrantLock 对象。

  2. 获取锁:在访问共享资源之前,线程必须通过调用 lock() 方法来获取锁。

  3. 重入获取锁:如果当前线程已经持有锁,再次调用 lock() 方法时,锁的计数会增加。

  4. 释放锁:线程完成对共享资源的访问后,必须通过调用 unlock() 方法来释放锁,锁的计数会减少。

  5. 锁的公平性:如果锁是公平的,那么等待时间最长的线程将会最先获取到锁。

示例代码

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockExample {

    // 创建锁对象,可以选择性地传入fair参数来指定是否公平
    private Lock lock = new ReentrantLock(true); // 公平锁

    public void performAction() {
        // 尝试获取锁
        lock.lock();
        try {
            // 线程安全地执行代码
            doSomething();
        } finally {
            // 释放锁
            lock.unlock();
        }
    }

    private void doSomething() {
        // 模拟一些操作
        System.out.println("Performing some action");
        // 假设需要再次获取锁进行操作
        lock.lock();
        try {
            // 再次执行线程安全的操作
            System.out.println("Performing another action");
        } finally {
            // 释放锁
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        ReentrantLockExample example = new ReentrantLockExample();
        example.performAction();
    }
}

注意事项

  1. 使用 ReentrantLock 时,务必在 finally 块中释放锁,以避免在发生异常时死锁。
  2. ReentrantLock 是一个重的锁,相比 synchronized,它在竞争激烈的情况下性能更好,但在低并发下,synchronized 的开销可能更小。
  3. 根据需要选择锁的公平性。非公平锁通常响应更快,但可能导致饥饿现象。

通过以上步骤和示例代码,你应该对 ReentrantLock 的工作原理有了清晰的理解。欢迎关注威哥爱编程,一起学习成长。