Sunday面试指南

Java AQS 是什么?它如何实现线程排队、阻塞和唤醒?

下面是一段教学用的模拟面试。

🧑‍💻 面试官:ReentrantLock 底层为什么会用到 AQS?

🙋‍♂️ 我:AQS 有一个队列,抢不到锁的线程就在里面排队。

🧑‍💻 面试官:那前一个线程释放锁,队首线程是不是就直接拿到锁了?

🙋‍♂️ 我:应该会被唤醒,然后拿到锁。

🧑‍💻 面试官:被唤醒和拿到锁是一回事吗?既然有 FIFO 队列,为什么 ReentrantLock 还分公平和非公平?

这道题要把两件事分开:「等到机会」和「获取成功」。队列组织等待,状态和获取规则决定谁能进入。

面试速答(60 秒版)

AQS 是 Java 用来构建锁、信号量等同步器的基础框架。它主要管理一个整型状态和等待队列,让获取失败的线程能够等待,并在资源释放后重新尝试。

但是,状态代表什么、怎样才算获取成功,需要具体同步器来定义。例如 ReentrantLock 用状态记录重入次数,Semaphore 用它表示剩余许可。

获取失败的线程可能进入队列并被阻塞;前面的线程释放资源后,等待线程被唤醒,再次检查能不能获取。唤醒不是把锁直接交给它。

同时,FIFO 队列也不等于默认公平。获取时是否允许新来的线程插队,要看同步器的策略。实际项目中通常使用成熟同步器,不会为了“底层用 AQS”就自己实现一把锁。

Q276 面试速答总览:已逐项目视核对对象、标签、箭头与正文关系。

知识点详解:AQS 怎样把资源状态和等待线程组织起来

先弄清楚 state 在记录什么

咱们假设两个线程都要修改同一份订单数据,需要先拿到一把 ReentrantLock。

没有线程持有锁时,状态可以理解为 0。T1 获取成功以后,状态变成 1,同时记录锁的持有者。如果 T1 再次获取同一把锁,状态继续增加,这就是重入。它也需要释放相同次数,状态回到 0 时,其他线程才有机会进入。

这里的 0、1 不是 AQS 强制规定的所有含义,而是这把锁的实现规则。如果换成 Semaphore,状态又可以表示剩余许可数量。因此,AQS 管理状态,但不替所有同步器定义状态的业务含义。

状态更新需要原子操作,避免两个线程同时看见空闲、同时宣布自己获取成功。不过,只会 CAS 还不够:总有线程获取失败,系统还得安排它怎样等。

获取失败以后,线程怎样等到下一次机会?

继续看 T1、T2。

T1 已经持有锁,T2 来获取。获取规则发现 T2 不是持有者,锁也没有空闲,因此这次失败。AQS 会把等待组织到同步队列中;等待过程中可能先做有限重试,然后在适当条件下通过 park 暂停线程,不需要一直占着 CPU 空转。

T1 释放锁后,如果锁已经完全释放,框架会安排唤醒等待线程。T2 从等待中回来以后,仍要重新执行获取逻辑。成功了才往下走;不成功就继续等待。

为什么还要检查?因为唤醒只代表“你可以再试了”。线程真正得到运行机会之前,资源状态可能已经变化;等待也不能依赖“每次醒来一定满足条件”这样的假设。

公平锁会在获取规则里考虑前面有没有等待者,尽量按等待顺序获取。非公平锁则允许新来的线程在某些时机先尝试。因此,AQS 官方 API 特别区分了队列顺序和获取策略,不能看到 FIFO 就推导出公平。

Q276 知识点示意:已逐项目视核对对象、标签、箭头与正文关系。

独占与共享,区别在于允许几个人进入

ReentrantLock 是独占同步的例子。同一时刻只有一个线程持有这把锁,但这个持有者可以重入。

Semaphore 可以作为共享同步的例子。假设只有两个许可,每个任务获取一个,那么两个任务可以一起运行,第三个需要等待。任务释放许可以后,后面的任务再尝试获取。

共享模式并不表示“所有线程都能同时进入”,也不等于一定读共享数据。它表示获取规则可以允许多个获取者同时满足条件。许可数量、一次申请几个许可,仍由同步器定义。

Q276 知识点示意:已逐项目视核对对象、标签、箭头与正文关系。

面试官继续追问

有了 CAS,为什么还需要等待队列?

CAS 解决一次状态修改能否成功,不负责组织长期竞争。如果所有失败线程一直重试,会浪费 CPU。队列与阻塞让失败线程能够等待,并把释放后的重试机会组织起来。

被唤醒的线程还是获取失败,会丢失唤醒吗?

不能把“收到一次唤醒”当作成功凭证。正确的同步框架会围绕状态检查、入队、阻塞和重试处理竞争,使用者也不能在自己的等待代码里省略条件检查。

公平锁一定更好吗?

公平更关注等待顺序,非公平可能减少交接带来的开销。要结合吞吐量、等待时间分布和是否能接受长期等待来判断,而不是只比较一次执行速度。

面试速记卡

  • AQS:管理同步状态、等待队列和等待重试的基础框架。
  • state:具体含义由同步器定义,不是所有场景都代表锁次数。
  • 获取失败:可以排队、阻塞,资源释放后再尝试。
  • 唤醒:恢复尝试的机会,不代表已经获取成功。
  • 公平:由获取策略保证,不能从 FIFO 队列直接推导。
  • 独占与共享:看获取规则允许多少获取者同时满足条件。

公司面试真题

真题根据求职者公开面经整理,题意经过概括,非逐字原话或公司官方题库;本文为 Sunday 的独立解析。

  • 阿里巴巴 · Java后端 · 社招

    ReentrantLock 怎样通过 AQS 实现公平、可重入和可中断锁?(题意整理)

    社招一年半面经分享 · 阿里部分 ↗
    历史面经,面试年份未明确;页面编辑于 2024-07-19

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历