ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
ReentrantLock 的实现原理主要依赖于 Java 中的 AbstractQueuedSynchronizer(AQS)类。AQS 是一个用于构建锁和同步器的框架,ReentrantLock 是基于 AQS 实现的可重入锁。 以下是 ReentrantLock 的一些关键实现原理: 1. 锁状态:ReentrantLock 使用一个整数来表示锁的状态。0 表示未锁定,1 表示已锁定。 2. 可重入性:通过维护一个线程持有锁的次数来实现可重入性。当一个线程获取锁时,锁状态增加;当线程释放锁时,锁状态减少。如果锁状态为 0,则表示锁已被完全释放。 3. 等待队列:当线程获取锁失败时,会被加入到一个等待队列中。等待队列是一个双向链表,按照先进先出的原则存储等待线程。 4. 锁获取:当一个线程尝试获取锁时,首先检查锁状态。如果锁未被占用,则直接获取锁并更新锁状态。如果锁已被其他线程占用,则根据公平性策略决定是否阻塞等待。公平性策略可以是公平的(按照线程请求锁的顺序分配锁)或非公平的(允许插队获取锁)。 5. 锁释放:当一个线程释放锁时,更新锁状态,并唤醒等待队列中的下一个线程(如果有)。 ### ReentrantLock 的实现原理 #### 1\. 基本概念 * **可重入**:同一个线程在持有锁的情况下,可以再次获得该锁,不会被阻塞。这解决了递归调用或者需要在锁内调用其他需要相同锁保护的方法时可能遇到的死锁问题。 * **公平锁与非公平锁**:`ReentrantLock` 可以支持公平锁和非公平锁。公平锁的策略是按照线程请求锁的顺序来分配锁,而非公平锁则可能会让后来的线程插队,从而提高吞吐量。默认情况下,`ReentrantLock` 是非公平锁。 #### 2\. 内部实现 `ReentrantLock` 的内部是通过继承自 `AbstractQueuedSynchronizer` (AQS) 来实现的。AQS 是一个提供锁和同步器底层支持的框架,`ReentrantLock` 使用 AQS 来实现其锁的管理。 ##### AQS (AbstractQueuedSynchronizer) AQS 使用一个 `int` 变量(`state`)来表示锁的状态,并通过 `FIFO` 队列来管理获取锁失败的线程。 * **state变量**:`state` 表示锁的状态,0 表示锁未被持有,1 表示锁被持有。对于可重入锁,`state` 的值表示当前线程获得锁的次数。 * **FIFO队列**:AQS 内部维护了一个 `FIFO` 队列,当一个线程请求锁失败时,线程会被加入到这个队列中等待锁的释放。 * **锁获取与释放**: * `acquire(int arg)`:尝试获取锁,锁不可用时将当前线程加入队列并阻塞。 * `release(int arg)`:释放锁,尝试唤醒队列中的下一个等待线程。 ##### 3\. ReentrantLock 的核心实现 `ReentrantLock` 通过内部的 `Sync` 类来实现锁的核心逻辑。`Sync` 继承自 AQS,分为两种实现:`FairSync` 和 `NonFairSync`,分别对应公平锁和非公平锁。 ###### 非公平锁(默认) ~~~ java复制代码static final class NonfairSync extends Sync { final void lock() { // 尝试直接获取锁(CAS操作),成功则立即获得锁,失败则调用acquire方法进入AQS逻辑 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } // 尝试获取锁 protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // 防止溢出 throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } } ~~~ * **非公平性**:`NonfairSync.lock()` 方法会直接尝试通过 `CAS` 操作获取锁(`compareAndSetState(0, 1)`),如果成功则立即获得锁,避免了公平锁的排队等待。如果失败,则调用 `acquire(1)` 进入 AQS 的逻辑,这一操作可能会将线程加入等待队列。 * **重入性**:`tryAcquire` 方法中,如果当前线程已经持有锁(即当前线程是锁的拥有者),则增加 `state` 的值,表示锁的重入。 ###### 公平锁 ~~~ java复制代码static final class FairSync extends Sync { final void lock() { acquire(1); } protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // 防止溢出 throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } } ~~~ * **公平性**:`FairSync.tryAcquire` 方法首先会检查 `hasQueuedPredecessors()`,即当前线程在等待队列中是否有前驱线程,如果有,则当前线程不能插队获取锁,必须排队等待。 ##### 4\. 锁的释放 锁的释放由 `Sync.release(int arg)` 方法实现。 ~~~ java复制代码protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; } ~~~ * **释放逻辑**:`tryRelease` 方法将 `state` 减去释放的次数。如果 `state` 的值降为 0,表示当前线程已经完全释放了锁,`setExclusiveOwnerThread(null)` 将锁的持有者设置为 `null`,然后返回 `true`,表示锁已完全释放。 #### 5\. 条件变量(Condition) `ReentrantLock` 支持条件变量(`Condition`),通过调用 `lock.newCondition()` 来创建。条件变量可以用来实现更细粒度的线程间通信。 * **await() 和 signal()**:`Condition` 提供了类似 `Object.wait()` 和 `Object.notify()` 的方法,比如 `await()` 和 `signal()`。当线程调用 `await()` 时,它会释放锁并进入等待状态,直到其他线程调用 `signal()` 唤醒它。 #### 6\. 总结 * **可重入性**:`ReentrantLock` 允许同一线程多次获取锁,内部通过 `state` 变量和线程持有者来管理。 * **公平与非公平**:`ReentrantLock` 可以在创建时指定是否为公平锁,通过不同的 `Sync` 实现来控制锁的公平性。 * **灵活性**:相比 `synchronized`,`ReentrantLock` 提供了更多控制和更高的灵活性,比如超时获取锁、可中断获取锁、条件变量等。