基本概念
ReentrantLock是Java并发包(java.util.concurrent.locks)中的一个可重入互斥锁实现,它提供了与synchronized关键字类似的功能,但具有更灵活的锁操作和更强大的功能。
核心实现原理
1. 基于AQS框架
ReentrantLock的核心实现依赖于AbstractQueuedSynchronizer(AQS)框架:
-
AQS提供了一个FIFO等待队列,用于管理获取锁失败的线程
-
通过state变量表示锁的状态(0表示未锁定,>0表示锁定状态和重入次数)
2. 可重入性实现
-
每次重入锁时,state值会递增
-
释放锁时,state递减,直到state=0时锁才完全释放
-
记录当前持有锁的线程,用于验证重入和释放锁的线程合法性
3. 公平锁与非公平锁
ReentrantLock提供了两种模式:
-
非公平锁(默认):
-
新请求线程可以立即尝试获取锁,不必排队
-
可能造成"插队"现象,但吞吐量更高
-
-
公平锁:
-
严格按照FIFO顺序获取锁
-
避免线程饥饿,但性能略低
-
关键方法实现
lock()方法
-
非公平锁实现:
-
首先尝试CAS快速获取锁
-
失败后进入AQS队列等待
-
-
公平锁实现:
-
直接检查是否有前驱节点
-
有则排队,无则尝试获取
-
unlock()方法
-
减少state值
-
当state=0时完全释放锁
-
唤醒队列中的下一个等待线程
与synchronized的对比优势
-
可中断的锁获取
-
超时获取锁
-
公平性选择
-
可以绑定多个Condition
适用场景
-
需要可中断锁获取时
-
需要尝试非阻塞获取锁时
-
需要公平锁时
-
需要更细粒度控制时
注意事项
-
必须在finally块中释放锁
-
避免锁的嵌套使用可能导致死锁
-
公平锁会带来性能开销
这样的回答既展示了技术深度,又体现了对实际应用的考虑,适合面试场景。