真实面经题目 · 原创解析

ReentrantLock 如何基于 AQS 实现可重入锁?

ReentrantLock 的核心不是自己从零管理阻塞队列,而是把获取锁、释放锁、排队、唤醒、可中断等待、条件队列等通用同步能力交给 AQS。它用 AQS 的 state 表示重入次数,用独占线程记录锁持有者,通过公平或非公平策略决定是否允许新线程插队。

出现于:字节跳动 · 后端开发

60 秒回答模板

可以从三层回答:第一,ReentrantLock 内部有一个 Sync 继承 AQS,公平锁和非公平锁分别实现不同的获取策略;第二,AQS 的 state 在这里表示锁的重入次数,state 为 0 表示未被占用,获取成功后设置当前线程为 owner,重入时只递增 state;第三,释放时逐层递减 state,只有减到 0 才清空 owner 并唤醒等待队列中的后继节点。所以 ReentrantLock 的可重入语义来自 state 计数,互斥语义来自 CAS 改 state 和 owner 校验,阻塞唤醒来自 AQS 的 FIFO 等待队列和 LockSupport。

考点 锁状态
难度 真实面经高频题
回答目标 讲清机制、边界和追问

深入解析

01

整体结构

ReentrantLock 本身主要是对外提供 Lock 接口能力,真正的同步逻辑在内部的 Sync 中完成。Sync 继承 AQS,公平锁 FairSync 和非公平锁 NonfairSync 再分别覆盖获取锁策略。这样设计的好处是锁不用重复实现等待队列、线程挂起、唤醒、取消等待等复杂逻辑,只要定义 state 如何表示资源、什么时候获取成功、什么时候释放成功。

02

state 的含义

在 ReentrantLock 里,AQS 的 state 不是资源数量,而是当前线程持有锁的重入次数。state 为 0 代表锁空闲,线程通过 CAS 把 state 从 0 改成 1 后成为独占持有者;如果同一个线程再次调用 lock,发现 owner 就是自己,就直接把 state 加 1。这个计数决定了释放时必须 unlock 相同次数,否则锁不会真正释放。

03

非公平获取

非公平锁的关键特点是新来的线程可以先尝试直接抢锁,不必先检查等待队列。它通常会先 CAS 把 state 从 0 改成 1,成功就设置 owner;失败后再走 AQS 的 acquire 流程进入队列。这样吞吐量通常更高,因为刚运行的线程可能直接继续执行,但等待时间不够稳定,队列中已经等待的线程可能被新线程插队。

04

公平获取

公平锁在尝试获取锁时会多一步判断:当前线程前面是否已有排队线程。如果队列中存在前驱等待者,即使 state 为 0,也不会直接抢占,而是按队列顺序获取。公平并不代表绝对实时调度,它只是尽量遵守 AQS 等待队列的先后关系,减少饥饿风险,代价是上下文切换和调度开销更明显,整体吞吐可能下降。

05

释放与唤醒

unlock 会调用 AQS 的 release,内部根据当前 state 减去一次重入计数。只有减到 0,才说明当前线程完全释放了锁,此时会清空独占线程,并唤醒等待队列中的后继节点。若非持有锁的线程调用 unlock,会抛出异常,因为释放逻辑必须校验 owner。Condition 也依赖 AQS,把等待条件的线程先放入条件队列,再在 signal 后转移到同步队列竞争锁。

易错点

  • 把 state 理解成锁对象本身,而不是 AQS 中可被子类定义语义的同步状态。
  • 认为可重入就是同一个线程重复排队获取锁,实际上同线程重入不会进入等待队列。
  • 忽略 unlock 次数必须和 lock 次数匹配,导致分析释放流程时过早认为锁已释放。
  • 把公平锁理解成性能更好,实际公平性通常会牺牲吞吐和调度效率。

面试官追问

为什么 ReentrantLock 可以重入?

因为它把 AQS 的 state 设计成持有次数,并记录独占线程。当前线程再次获取时不需要排队,只要确认 owner 是自己,然后增加 state。

为什么 unlock 必须调用多次?

一次 lock 对应一次 state 增加,一次 unlock 只减少一层重入计数。只有 state 减到 0,锁才真正释放并唤醒后继线程。

公平锁一定不会插队吗?

公平锁会在获取时检查等待队列,尽量让排队更久的线程先获得锁,但线程调度仍由操作系统决定,所以它不是严格实时公平。

Condition 和 synchronized 的 wait 有什么关系?

Condition 类似更灵活的等待通知机制。一个 ReentrantLock 可以创建多个 Condition,每个 Condition 有自己的条件队列,而 synchronized 每个对象只有一个等待集合。