ReentrantLock
是 Java 中的一个接口,属于 java.util.concurrent.locks
包。它提供了一种锁机制,用于控制多个线程对共享资源的访问。与 Java 中的 synchronized
关键字相比,ReentrantLock
提供了更复杂的锁定机制,并且允许中断、超时以及尝试非阻塞地获取锁。
以下是 ReentrantLock
的一些关键特性和使用方法的详解:
特性:
重入:正如其名称所示,
ReentrantLock
允许同一个线程多次获取锁,每获取一次,锁的计数器就增加一,只有当锁的计数器下降到零时,其他线程才有机会获取该锁。公平性:可以设置公平性。如果设置为公平锁,则等待时间最长的线程(或最先请求锁的线程)将最先获得锁。如果设置为非公平锁(默认),则获取锁的顺序可能是随机的。
可中断:获取锁的过程中,线程可以选择中断,当线程被中断时,它会抛出
InterruptedException
。超时:在尝试获取锁时,可以指定一个超时时间,在超时时间内如果未能获取到锁,将抛出
TimeoutException
。非阻塞尝试获取:可以尝试在不阻塞的情况下获取锁,如果锁不可用,调用立即返回
false
。
使用方法:
创建 ReentrantLock:
ReentrantLock lock = new ReentrantLock();
或者创建一个公平锁:
ReentrantLock lock = new ReentrantLock(true);
锁的获取与释放:
lock.lock(); // 获取锁
try {
// 执行受保护的代码
} finally {
lock.unlock(); // 释放锁
}
尝试非阻塞获取锁:
if (lock.tryLock()) {
try {
// 执行受保护的代码
} finally {
lock.unlock();
}
} else {
// 处理锁不可用的情况
}
锁的中断获取:
lock.lockInterruptibly(); // 可中断地获取锁
try {
// 执行受保护的代码
} catch (InterruptedException e) {
// 处理中断
} finally {
lock.unlock();
}
超时获取锁:
try {
if (lock.tryLock(1, TimeUnit.SECONDS)) {
// 超时时间为1秒
try {
// 执行受保护的代码
} finally {
lock.unlock();
}
} else {
// 处理超时情况
}
} catch (InterruptedException e) {
// 处理中断
}
与其他锁比较:
synchronized
是一种内置的、无公平性的锁,它不支持超时和中断。java.util.concurrent.locks.Lock
接口(ReentrantLock
实现了这个接口)提供了比synchronized
更高级的特性,如公平性、中断、超时等。
注意事项:
- 使用
ReentrantLock
时,必须确保在每个lock()
调用后都有相应的unlock()
调用,以避免死锁。 - 推荐使用
try-finally
块来确保即使发生异常也能释放锁。 - 在设计锁的时候,尽量减少锁的持有时间和粒度,以减少线程间的等待时间,提高并发效率。
ReentrantLock
是 Java 并发编程中一个非常有用的工具,它提供了比 synchronized
更多的灵活性,使得开发者可以根据需要实现更复杂的同步需求。