大家好,我是锋哥。今天分享关于【什么是可重入锁ReentrantLock?】面试题。希望对大家有帮助;
什么是可重入锁ReentrantLock?
ReentrantLock
是 Java 中的一个锁实现,它是 java.util.concurrent.locks
包中的一部分,主要用于提供比传统的 synchronized
关键字更加灵活的锁机制。正如它的名字所示,ReentrantLock
是一种 可重入锁,即同一个线程可以多次获得同一把锁,而不会发生死锁。
1. 可重入锁的定义
- 可重入性:当一个线程已经持有某个锁时,它可以再次请求这个锁,而不会被阻塞。线程再次请求锁时,锁的计数器会增加,当线程释放锁时,锁的计数器会减少。只有当计数器归零时,锁才会被释放。
2. ReentrantLock 的主要特点
- 可重入性:同一个线程可以多次获得同一个锁。每次获得锁时,锁的计数器会增加,直到释放锁时,计数器归零。
- 显式加锁与解锁:与
synchronized
关键字不同,ReentrantLock
需要显式调用lock()
方法来加锁,调用unlock()
方法来释放锁。 - 公平性:
ReentrantLock
提供了一个可选的公平性策略。公平锁保证了线程按照请求锁的顺序依次获得锁,而非公平锁则可能导致线程的饥饿问题(即有的线程一直得不到锁)。你可以在创建ReentrantLock
时选择是否设置为公平锁:new ReentrantLock(true)
为公平锁;new ReentrantLock(false)
为非公平锁(默认)。
- 中断响应:
ReentrantLock
提供了一个方法lockInterruptibly()
,它可以响应中断。如果一个线程在等待获取锁的过程中被中断,它可以及时退出等待,避免死锁或长时间阻塞。
3. ReentrantLock 的常用方法
lock()
: 获取锁。如果锁被其他线程持有,当前线程会阻塞,直到获得锁。unlock()
: 释放锁。每个调用lock()
的线程必须调用unlock()
来释放锁,否则会导致死锁。tryLock()
: 尝试获取锁,若锁已被其他线程占用,则立即返回false
。该方法可以设置超时时间来避免无限等待。lockInterruptibly()
: 获取锁,但如果线程在等待过程中被中断,能够响应并退出等待。
4. 示例代码
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockExample {
private static ReentrantLock lock = new ReentrantLock();
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
// 第一次加锁
lock.lock();
try {
System.out.println("Thread 1: Acquired lock for the first time");
// 第二次加锁
lock.lock();
try {
System.out.println("Thread 1: Acquired lock for the second time");
} finally {
lock.unlock(); // 第二次释放锁
}
} finally {
lock.unlock(); // 第一次释放锁
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
lock.lock();
try {
System.out.println("Thread 2: Acquired lock");
} finally {
lock.unlock(); // 释放锁
}
}
});
t1.start();
t2.start();
}
}
5. 使用场景
ReentrantLock
在以下场景中特别有用:
- 当需要对锁的获取和释放过程进行更加精细的控制时,例如,明确的超时策略或响应中断的能力。
- 需要实现公平锁的场合,避免某些线程长时间无法获得锁。
- 当要控制并发访问的情况下,提供比
synchronized
更大的灵活性。
总结
ReentrantLock
是一种更为灵活的锁实现,相比于传统的 synchronized
锁,它提供了更多的控制能力,比如可重入性、超时机制、公平性、响应中断等。因此,ReentrantLock
常常用于复杂的多线程场景中,尤其是那些需要高控制力和高效的并发控制的情况。