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 对象来实现线程间的协调,这类似于 Object
的 wait()
和 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
块中释放锁,以确保即使在出现异常时锁也能被正确释放,避免死锁问题。