当前位置: 面试刷题>> Java 中 ReentrantLock 的实现原理是什么?
在深入探讨Java中`ReentrantLock`的实现原理时,我们首先需要理解其作为并发工具的核心价值和设计目标。`ReentrantLock`是java.util.concurrent.locks包下的一个类,它提供了一种比synchronized关键字更灵活的锁机制。与synchronized不同,`ReentrantLock`是显式的锁,它提供了更多的特性,如尝试非阻塞地获取锁(tryLock)、可中断的锁获取(lockInterruptibly)、定时锁获取(tryLock带超时参数)以及条件变量(Condition)等。
### ReentrantLock的核心原理
#### 1. 锁的内部实现
`ReentrantLock`的实现依赖于AbstractQueuedSynchronizer(简称AQS),一个用于构建锁和其他同步类的框架。AQS维护了一个volatile int state(状态)来表示同步状态,对于`ReentrantLock`而言,这个状态表示锁被持有的次数(重入次数)。当state为0时,表示锁未被任何线程持有;当state大于0时,表示锁已被持有,且state的值表示重入的次数。
#### 2. 锁的获取与释放
- **获取锁**:当线程尝试通过`lock()`方法获取锁时,如果当前锁未被任何线程持有(state为0),则将该线程的标识与锁关联,并设置state为1,表示锁已被该线程持有。如果锁已被其他线程持有,则当前线程将被挂起(通过AQS的CLH队列实现),直到锁被释放且该线程被唤醒。
- **释放锁**:当线程通过`unlock()`方法释放锁时,它会减少state的值。如果state变为0,则表示锁已被完全释放,此时AQS会唤醒在CLH队列中等待的下一个线程(如果有的话)。
#### 3. 可重入性
`ReentrantLock`支持可重入性,即同一个线程可以多次获得同一个锁。这是通过检查当前线程是否已经是锁的持有者来实现的。如果是,则简单地增加state的值(重入次数),而不是将线程挂起。
#### 4. 公平性
`ReentrantLock`支持公平锁和非公平锁两种模式。默认情况下,它采用非公平锁模式,即线程以插队的方式尝试获取锁,这可以提高吞吐量但可能导致某些线程长时间等待。公平锁模式则会按照线程请求锁的顺序来授予锁,这有助于减少饥饿,但可能会降低吞吐量。
### 示例代码
下面是一个简单的使用`ReentrantLock`的示例,展示了其基本用法:
```java
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Counter {
private final Lock lock = new ReentrantLock(); // 创建一个ReentrantLock实例
private int count = 0;
public void increment() {
lock.lock(); // 显式地获取锁
try {
count++; // 临界区
} finally {
lock.unlock(); // 无论是否发生异常,都释放锁
}
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
// 使用多个线程来修改counter的count
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
counter.increment();
}
});
threads[i].start();
}
// 等待所有线程完成
for (Thread thread : threads) {
thread.join();
}
System.out.println("Final count: " + counter.getCount()); // 应该接近10000
}
}
```
在这个示例中,`Counter`类使用`ReentrantLock`来保护其共享资源`count`,防止在并发环境下出现数据不一致的问题。通过显式地调用`lock()`和`unlock()`,我们能够精确控制锁的获取和释放时机,确保线程安全。
### 总结
`ReentrantLock`通过内部使用AQS框架,实现了高效的线程同步。它提供了比synchronized关键字更丰富的功能,包括可重入性、可中断的锁获取、定时锁获取以及公平锁等特性。这些特性使得`ReentrantLock`成为处理复杂并发场景时的有力工具。在设计和实现并发应用时,深入理解`ReentrantLock`的原理和使用方法,对于提升应用的性能和稳定性至关重要。