ReentrantLock 锁详细介绍

35 阅读2分钟

ReentrantLock 是 Java 中 java.util.concurrent.locks 包提供的一种锁实现,它是 Java 并发编程中用于替代 synchronized 关键字的锁机制。与 synchronized 不同,ReentrantLock 提供了更高级的锁操作功能,比如可重入性、可定时锁、可中断锁请求以及多个条件变量等。下面是对 ReentrantLock 的详细介绍:

1. 可重入性

ReentrantLock 是可重入的,这意味着同一线程可以多次获得同一把锁,而不会导致死锁。这与 synchronized 的行为类似。每次线程进入锁定的代码块,锁的获取计数都会增加,退出时计数减少,直到计数为零时,锁才会被释放。

2. 锁获取方式

ReentrantLock 提供了多种方式来获取锁:

  • lock():如果锁不可用,则线程将被阻塞,直到获得锁。
  • lockInterruptibly():与 lock() 类似,但在等待过程中可以响应中断。
  • tryLock():尝试获取锁,如果锁可用,则立即获取锁并返回 true,否则返回 false
  • tryLock(long timeout, TimeUnit unit):在指定的时间内尝试获取锁,超时后返回 false

3. 锁释放

  • unlock():释放锁。只有持有锁的线程才能调用这个方法,否则会抛出 IllegalMonitorStateException

4. 条件变量

ReentrantLock 提供了 Condition 对象来实现线程间的协调,这类似于 Objectwait()notify() 方法。可以通过 newCondition() 方法创建一个或多个条件变量。常用的方法包括:

  • await():使当前线程等待,直到被通知或中断。
  • signal():唤醒一个等待线程。
  • signalAll():唤醒所有等待线程。

5. 公平锁和非公平锁

ReentrantLock 可以配置为公平锁或非公平锁:

  • 公平锁:线程获取锁的顺序是按照请求锁的顺序(FIFO)进行的。
  • 非公平锁(默认):可能会使某些线程长时间等待,但通常具有更高的吞吐量。

可以通过构造函数来指定锁的公平性:

ReentrantLock lock = new ReentrantLock(true); // 公平锁
ReentrantLock lock = new ReentrantLock(); // 非公平锁

6. 性能和使用场景

ReentrantLock 提供了比 synchronized 更灵活和强大的功能,因此在需要精细控制锁行为的场景中非常有用。然而,它的使用也更复杂,需要显式地获取和释放锁,容易出现死锁和锁泄漏问题。

使用示例

ReentrantLock lock = new ReentrantLock();

public void someMethod() {
    lock.lock();
    try {
        // 需要同步的代码块
    } finally {
        lock.unlock();
    }
}

在使用 ReentrantLock 时,务必在 finally 块中释放锁,以确保即使在出现异常时锁也能被正确释放,避免死锁问题。

7. 参考

Condition 详细介绍