请解释 Java 中 ReentrantLock 的实现原理,包括其内部同步器、加锁与释放锁的过程、重入性、公平与不公平策略,以及它与 synchronized 的主要区别。
考察说明
考查对 ReentrantLock 底层同步机制、公平性设计和锁重入原理的理解。
回答思路
- 【回答框架 1】ReentrantLock 基于 AbstractQueuedSynchronizer(AQS)实现,内部维护一个 volatile 状态变量 state 和等待队列。加锁时通过 CAS 尝试将 state 从 0 改为 1,成功则获得锁;失败则封装为节点进入同步队列,并可能阻塞线程(LockSupport.park)。
- 【回答框架 2】重入性通过 state 计数体现:同一线程重复获取锁时 state 递增,释放时递减,直到变为 0 才真正释放锁。需要用持有线程的引用(如 exclusiveOwnerThread)来判断当前线程是否持有锁,避免其他线程错误重入。
- 【回答框架 3】公平与非公平策略在于获取锁的时机:非公平锁在加锁时先直接尝试 CAS,若成功则抢占锁;公平锁则先检查队列中是否有前驱节点,若无则再尝试 CAS。因此公平锁基于队列顺序获取锁,非公平锁允许新线程抢在队列头部线程之前获得锁,性能更优但可能造成饥饿。
- 【回答框架 4】ReentrantLock 还提供中断响应(lockInterruptibly)、超时获取(tryLock)和条件变量(Condition)等高级功能,这些也是其与 synchronized 的重要差异。synchronized 是隐式监视器锁,而 ReentrantLock 是显式锁,需手动加锁和释放。
- 【关键点 1】ReentrantLock 基于 AQS,state 记录持有次数,CAS 加锁。
- 【关键点 2】重入通过 state 计数和 exclusiveOwnerThread 判断实现。
- 【关键点 3】公平锁先查队列,非公平锁先抢锁,性能与公平性侧重不同。
- 【关键点 4】支持中断、超时和 Condition,提供更多控制能力。
- 【易错点 1】忘记在 finally 中释放锁会导致死锁。
- 【易错点 2】公平锁并非绝对顺序,线程可能因挂起和唤醒延迟出现乱序。
- 【易错点 3】条件变量调用 signal 时需持有锁,否则抛出 IllegalMonitorStateException。