ReentrantLock 是 Java 中基于 AQS(AbstractQueuedSynchronizer) 实现的一种可重入独占锁。它提供了比 synchronized
更灵活的锁机制,支持公平锁和非公平锁,并且可以响应中断、设置超时等。
1. ReentrantLock 的核心特性
- 可重入性:
- 同一个线程可以多次获取同一把锁,而不会造成死锁。
- 每次获取锁后,锁的持有计数(
state
)加 1;每次释放锁后,计数减 1。
- 公平性:
- 公平锁:按照线程请求锁的顺序分配锁。
- 非公平锁:允许插队,新请求的线程可以直接尝试获取锁。
- 支持中断:
- 线程在等待锁的过程中可以响应中断。
- 支持超时:
- 线程可以尝试在指定时间内获取锁,超时后放弃。
2. ReentrantLock 的实现原理
- 基于 AQS:
ReentrantLock
的核心功能是通过 AQS 实现的。- AQS 提供了一个
state
变量来表示锁的状态,以及一个 CLH 队列来管理等待锁的线程。
- 独占模式:
ReentrantLock
使用 AQS 的独占模式,同一时刻只有一个线程可以持有锁。
- 可重入性:
- 通过
state
变量记录锁的重入次数。每次获取锁时,state
加 1;每次释放锁时,state
减 1。
- 通过
3. ReentrantLock 的源码分析
- Sync 内部类:
ReentrantLock
的核心功能是通过Sync
内部类实现的,Sync
继承自 AQS。Sync
有两个子类:NonfairSync
(非公平锁)和FairSync
(公平锁)。
- 非公平锁的实现:
- 新请求的线程可以直接尝试获取锁,如果失败则加入队列。
- 源码片段:
final void lock() { if (compareAndSetState(0, 1)) // CAS 尝试获取锁 setExclusiveOwnerThread(Thread.currentThread()); // 设置当前线程为锁持有者 else acquire(1); // 调用 AQS 的 acquire 方法 }
- 公平锁的实现:
- 新请求的线程必须加入队列,按照 FIFO 顺序获取锁。
- 源码片段:
final void lock() { acquire(1); // 直接调用 AQS 的 acquire 方法 }
4. ReentrantLock 的使用示例
- 基本用法:
ReentrantLock lock = new ReentrantLock(); lock.lock(); // 获取锁 try { // 临界区代码 } finally { lock.unlock(); // 释放锁 }
- 支持中断:
ReentrantLock lock = new ReentrantLock(); try { lock.lockInterruptibly(); // 可中断地获取锁 // 临界区代码 } catch (InterruptedException e) { // 处理中断 } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); // 释放锁 } }
- 支持超时:
ReentrantLock lock = new ReentrantLock(); try { if (lock.tryLock(1, TimeUnit.SECONDS)) { // 尝试在 1 秒内获取锁 // 临界区代码 } else { // 超时处理 } } catch (InterruptedException e) { // 处理中断 } finally { if (lock.isHeldByCurrentThread()) { lock.unlock(); // 释放锁 } }
5. ReentrantLock 与 synchronized 的对比
特性 | ReentrantLock | synchronized |
---|---|---|
实现方式 | 基于 AQS,Java 代码实现 | JVM 内置实现 |
可重入性 | 支持 | 支持 |
公平性 | 支持公平锁和非公平锁 | 仅支持非公平锁 |
支持中断 | 支持 | 不支持 |
支持超时 | 支持 | 不支持 |
性能 | 高并发下性能更好 | 低并发下性能更好 |
锁绑定条件 | 支持多个条件变量(Condition ) | 不支持 |
6. ReentrantLock 的优缺点
- 优点:
- 提供了比
synchronized
更灵活的锁机制。 - 支持公平锁、可中断、超时等特性。
- 在高并发场景下性能优异。
- 提供了比
- 缺点:
- 使用复杂,需要手动加锁和释放锁。
- 容易忘记释放锁,导致死锁。
7. 总结
- ReentrantLock 是基于 AQS 实现的可重入独占锁,支持公平锁和非公平锁。
- 它提供了比
synchronized
更灵活的锁机制,支持中断、超时等特性。 - 在高并发场景下,
ReentrantLock
的性能通常优于synchronized
。 - 使用
ReentrantLock
时需要注意手动加锁和释放锁,避免死锁问题。
8. 扩展:Condition 的使用
ReentrantLock
支持多个条件变量(Condition
),用于实现线程间的精确唤醒。- 示例代码:
ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); lock.lock(); try { condition.await(); // 当前线程等待 condition.signal(); // 唤醒一个等待线程 } finally { lock.unlock(); }
THE END
暂无评论内容