在Java并发编程中,ReentrantLock 是一个功能强大的同步工具,它提供了比 synchronized 关键字更为丰富的功能。ReentrantLock 是 java.util.concurrent.locks 包中的一个类,它允许完全的轮询和定时锁等候,以及可中断的锁定和尝试(非阻塞)锁定。通过使用 ReentrantLock,我们可以实现更复杂的线程同步策略,提高程序的性能和灵活性。本文将深入探讨 ReentrantLock 的使用,并通过示例来演示如何利用它来实现高级锁功能。
ReentrantLock 简介
ReentrantLock 是一种可重入互斥锁,它拥有与 synchronized 相同的基本行为和语义,但功能更加强大。其特点包括:
- 可响应性:锁可以由未持有锁的线程释放,这减少了锁不必要的保持时间。
- 可中断性:一个正在等待锁的线程可以被中断。
- 公平性:锁可以设置为公平锁或非公平锁。
- 条件变量:
ReentrantLock配合Condition接口提供了比Object的wait()、notify()和notifyAll()方法更强大的等待/通知机制。
使用 ReentrantLock
创建和使用
创建一个 ReentrantLock 对象非常简单:
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();
public void performTask() {
lock.lock(); // 获取锁
try {
// 执行临界区代码
} finally {
lock.unlock(); // 释放锁
}
}
}
在上面的例子中,我们首先创建了一个 ReentrantLock 对象。然后,在 performTask 方法中,使用 lock() 方法获取锁,并在 finally 块中使用 unlock() 方法释放锁,以确保锁最终会被释放。
公平性和非公平性
ReentrantLock 可以配置为公平锁或非公平锁。公平锁意味着等待时间最长的线程会先获得锁。这对于避免线程饥饿很有用,但可能会牺牲一些性能。默认情况下,ReentrantLock 是非公平的。
// 创建一个公平的 ReentrantLock
ReentrantLock fairLock = new ReentrantLock(true);
可中断的锁定
与 synchronized 不同,ReentrantLock 允许线程在等待锁时被中断。这提供了一种避免死锁的策略。
lock.lockInterruptibly(); // 可以被中断的锁定
尝试锁定
tryLock() 方法尝试立即获得锁,如果成功则返回 true,否则返回 false。这种非阻塞的方式对于减少等待时间和提高响应性非常有用。
if (lock.tryLock()) {
try {
// 执行临界区代码
} finally {
lock.unlock();
}
} else {
// 无法获得锁,采取其他行动
}
条件变量
与 synchronized 配合 Object 的 wait()、notify() 和 notifyAll() 不同,ReentrantLock 使用 Condition 接口来实现更灵活的等待/通知模式。
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
lock.lock();
try {
while (/* 条件不满足 */) {
condition.await(); // 等待条件成立
}
// 执行临界区代码
} finally {
lock.unlock();
}
在上面的代码中,我们首先创建了 ReentrantLock 和相关的 Condition 对象。当某个条件不满足时,线程可以在 condition.await() 上等待,直到其他线程调用 condition.signal() 或 condition.signalAll() 方法。
结论
ReentrantLock 提供了比 synchronized 更加丰富和灵活的线程同步机制。通过使用 ReentrantLock,开发者可以更好地控制锁的行为,实现公平性、可中断性、尝试锁定和非阻塞等待等功能。这些高级特性使得 ReentrantLock 成为构建高性能并发应用程序的强有力工具。然而,使用 ReentrantLock 需要谨慎,因为它比 synchronized 更容易出错,特别是在涉及多个条件变量时。正确使用 ReentrantLock 要求对其底层原理有深入的理解,并且能够识别适合使用高级锁功能的场景。