在Java并发编程中,锁是保证数据在多线程环境下一致性和安全性的重要机制。Java标准库提供了多种锁的实现,其中ReentrantLock是可重入锁的一个典型实现,它属于java.util.concurrent.locks包。相比于内置的synchronized关键字,ReentrantLock提供了更灵活和强大的功能。
1. 可重入锁的概念
可重入锁(ReentrantLock)允许同一线程多次获取同一把锁,而不会造成死锁。这种特性使得锁在同一线程内可以被递归使用,从而避免了在递归调用时可能出现的死锁问题。
2. ReentrantLock的基本使用
使用ReentrantLock的基本步骤如下:
- 创建一个
ReentrantLock对象。 - 在需要加锁的代码块前调用
lock()方法获取锁。 - 在需要释放锁的代码块后调用
unlock()方法释放锁。
示例代码:
java复制代码
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();
public void someMethod() {
lock.lock(); // 获取锁
try {
// 临界区,同一时间只有一个线程能执行这里的代码
// ...
} finally {
lock.unlock(); // 释放锁
}
}
// 递归调用示例
public void recursiveMethod() {
lock.lock();
try {
// ...
recursiveMethod(); // 递归调用自身,仍然可以获取锁
// ...
} finally {
lock.unlock();
}
}
}
3. ReentrantLock的特性
- 可重入性:同一个线程可以多次获取同一把锁,而不会被阻塞。
- 公平锁与非公平锁:
ReentrantLock可以构造为公平锁或非公平锁。公平锁会按照线程请求锁的顺序来分配锁,而非公平锁则可能允许插队,即新请求的线程可能会立即获取锁,而等待时间较长的线程可能会继续等待。默认情况下,ReentrantLock是非公平锁。 - 中断响应:与
synchronized不同,ReentrantLock支持对等待锁的线程进行中断。 - 尝试锁:
ReentrantLock提供了tryLock()方法,该方法会尝试获取锁,如果锁当前可用则获取锁并立即返回true,否则立即返回false。 - 定时锁:
ReentrantLock还提供了tryLock(long timeout, TimeUnit unit)方法,该方法会尝试获取锁,但如果在给定的等待时间内仍然没有获取到锁,则返回false。
4. ReentrantLock与synchronized的比较
synchronized是Java内置的关键字,使用方便但功能有限;而ReentrantLock是Java标准库中的一个类,提供了更多的功能。ReentrantLock支持公平锁和非公平锁,而synchronized只有非公平锁。ReentrantLock支持对等待锁的线程进行中断,而synchronized不支持。ReentrantLock提供了更灵活的锁控制,如尝试锁和定时锁,而synchronized不支持这些功能。
5. 总结
ReentrantLock作为Java中的一个可重入锁实现,提供了比synchronized更强大和灵活的功能。在需要更精细控制锁的行为时,使用ReentrantLock是一个很好的选择。然而,由于其使用相对复杂,需要确保在finally块中释放锁,以避免潜在的死锁问题。