1. 基本功能
ReentrantLock
提供了以下功能:
- 显式锁管理:需要手动加锁和解锁
- 可重入性:同一线程可以多次获取同一个锁,并且不会发生死锁
- 公平性:可以选择公平锁,保证线程按照请求锁的顺序获取锁
- 中断锁获取:可以在等待锁的过程中响应中断
- 定时锁获取:可以设定超时时间,超时未获取到锁则返回失败
2. 创建 ReentrantLock 实例
可以通过无参构造函数或带 boolean
类型参数的构造函数创建 ReentrantLock
实例:
非公平锁(默认):
ReentrantLock lock = new ReentrantLock();
公平锁:
ReentrantLock fairLock = new ReentrantLock(true);
3. 基本用法
1、加锁和解锁
使用 lock()
方法加锁,使用 unlock()
方法解锁。通常在 try-finally
块中使用,以确保锁能够正确释放
ReentrantLock lock = new ReentrantLock();
public void method() {
lock.lock(); // 加锁
try {
// 代码
} finally {
lock.unlock(); // 解锁
}
}
2、可中断锁获取
使用 lockInterruptibly()
方法,可以在等待获取锁时响应中断
try {
lock.lockInterruptibly();
try {
// 代码
} finally {
lock.unlock();
}
} catch (InterruptedException e) {
// 处理中断
}
3、尝试获取锁
使用 tryLock()
方法尝试获取锁,如果获取不到立即返回 false
if (lock.tryLock()) {
try {
// 代码
} finally {
lock.unlock();
}
} else {
// 获取锁失败,处理逻辑
}
4、定时获取锁
使用 tryLock(long timeout, TimeUnit unit)
方法,在指定时间内尝试获取锁,超时未获取到锁则返回 false
try {
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try {
// 代码
} finally {
lock.unlock();
}
} else {
// 获取锁失败,处理逻辑
}
} catch (InterruptedException e) {
// 处理中断
}
4. 条件变量
ReentrantLock
支持条件变量,通过 newCondition()
方法创建 Condition
对象,可以实现更加灵活的线程间通信机制
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
public void awaitMethod() throws InterruptedException {
lock.lock();
try {
condition.await(); // 当前线程等待,直到被唤醒
} finally {
lock.unlock();
}
}
public void signalMethod() {
lock.lock();
try {
condition.signal(); // 唤醒一个等待线程
} finally {
lock.unlock();
}
}
5. 公平锁 vs 非公平锁
- 非公平锁:线程获取锁的顺序不保证,是默认行为,可能导致线程饥饿
- 公平锁:保证线程按照请求锁的顺序获取锁,避免线程饥饿,可能导致性能下降
6. ReentrantLock 的其他方法
int getHoldCount()
:返回当前线程持有该锁的次数boolean isHeldByCurrentThread()
:判断当前线程是否持有该锁boolean isLocked()
:判断该锁是否被任何线程持有boolean hasQueuedThreads()
:判断是否有线程在等待获取该锁int getQueueLength()
:返回等待获取该锁的线程数
总结
ReentrantLock
提供了比 synchronized
更加灵活和强大的锁机制,可以处理更多复杂的并发场景。它适用于需要高性能和更高级锁特性的场合,如可中断的锁获取、定时锁获取和公平锁等。正确使用 ReentrantLock
,可以显著提高并发程序的可靠性和性能。
以下是一个完整示例,展示了 ReentrantLock
的常见用法:
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private final ReentrantLock lock = new ReentrantLock();
public void safeMethod() {
lock.lock();
try {
// 代码
System.out.println("Thread " + Thread.currentThread().getName() + " is in critical section.");
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLockExample example = new ReentrantLockExample();
Runnable task = () -> {
for (int i = 0; i < 5; i++) {
example.safeMethod();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
}
}