ReentrantLock是Java并发包java.util.concurrent.locks中的一个类,它实现了Lock接口,提供了一种与Synchronized方法和语句相同的基本行为和语义的互斥锁,但具有更多的扩展功能。
主要特点
- 可重入性
与 synchronized 关键字一样,ReentrantLock 允许同一个线程多次获得锁,而不会发生死锁。每次成功获取锁后,锁的持有计数会增加,每次释放锁时,计数会减少。只有当计数为0时,锁才完全释放,其他线程才能获取该锁。 - 公平性
ReentrantLock 构造函数接受一个可选的 boolean 类型的 fairness 参数。如果设置为 true,则锁将按照请求锁的顺序(即等待时间最长的线程将优先获得锁),来授予访问权限。这有助于减少饥饿现象,但可能会降低吞吐量。如果设置为 false(默认值),则不保证任何特定的访问顺序。 - 尝试非阻塞地获取锁
ReentrantLock 提供了 tryLock() 方法,该方法尝试获取锁,如果锁可用,则立即返回 true,否则立即返回 false。这与 synchronized 关键字不同,后者在锁不可用时会使线程阻塞。 - 可中断的锁获取
ReentrantLock 支持可中断的锁获取操作,即线程在等待锁的过程中可以被中断。这通过 lockInterruptibly() 方法实现,如果当前线程在等待锁的过程中被中断,则会抛出 InterruptedException。 - 条件变量
与 synchronized 关键字不同,ReentrantLock 提供了条件变量(Condition),允许多个条件等待集。这允许更灵活的线程同步控制。
使用建议
- 防止死锁
使用try-finally语句,在调用lock()方法后,应立即使用try-finally语句来确保锁最终会被释放; - 考虑公平性
如果实际应用场景中,锁的获取顺序很重要,或者希望减少饥饿现象,可以考虑将 fairness 参数设置为 true。但请注意,这可能会降低系统的吞吐量。 - 避免过度使用
虽然 ReentrantLock提供了比synchronized更多的功能,但过度使用可能会使代码变得复杂且难以维护。在大多数情况下,synchronized 关键字已经足够使用。
示例代码
class ReentrantLockSample {
// 默认非公平锁
private final ReentrantLock lock = new ReentrantLock();
// 公平锁
// private final ReentrantLock lock = new ReentrantLock(true);
public void method() {
// 尝试获取锁
lock.lock();
try {
// ... 方法体
} finally {
// 释放锁
lock.unlock();
}
}
}
在这个例子中,lock.lock() 尝试获取锁,如果锁被其他线程持有,则当前线程将阻塞,直到锁被释放。在 try 块中执行的方法体完成后,无论是否发生异常,finally 块都会确保锁被释放。
标签:重入,synchronized,lock,ReentrantLock,获取,finally,线程 From: https://www.cnblogs.com/demon001/p/18404226