当前位置: 面试刷题>> 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`的原理和使用方法,对于提升应用的性能和稳定性至关重要。
推荐面试题