8.7 KiB
tags, create time
| tags | create time | ||||||
|---|---|---|---|---|---|---|---|
|
2026-08-09 12:00 |
锁升级与 CAS 机制_测试题
概述
本测试覆盖 synchronized 锁升级机制(偏向→轻量级→重量级)、CAS 原子操作原理、ABA 问题及其解决方案、AQS 框架设计等核心内容,共 10 道题目(6 道选择题 + 3 道填空题 + 1 道简答题)。
一、选择题(6道,由浅入深)
难度阶梯: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景
Q1(基础)— 考察定义层面
synchronized 锁升级的正确顺序是:
A. 重量级 → 轻量级 → 偏向锁
B. 偏向锁 → 轻量级 → 重量级
C. 轻量级 → 偏向锁 → 重量级
D. 偏向锁 → 重量级 → 轻量级
Q2(基础)— 考察概念记忆
关于偏向锁,以下说法正确的是:
A. JDK 17 中仍然默认启用,通过 -XX:+UseBiasedLocking 控制
B. 偏向锁撤销时需要全局 STW,代价较高,因此在真实场景中很少能发挥优势
C. 偏向锁状态下,同一线程重复获取锁也需要进行一次 CAS 操作
D. 当有其他线程尝试获取偏向锁时,当前锁会直接升级为重量级锁
Q3(进阶)— 考察核心原理
在轻量级锁获取过程中,线程首先在栈帧中创建 Lock Record,然后使用 CAS 将对象头的 Mark Word 替换为指向 Lock Record 的指针。如果 CAS 失败,接下来会发生什么?
A. 立即升级为重量级锁
B. 线程进入睡眠状态等待其他线程释放锁
C. 当前线程自旋重试(最多循环指定次数)
D. 抛出 ConcurrencyModificationException 异常
Q4(进阶)— 考察比较与辨析
synchronized 关键字与 ReentrantLock 的主要区别,以下描述错误的是:
A. synchronized 是 JVM 内置关键字,ReentrantLock 是 JDK API 层的实现
B. synchronized 支持锁升级(偏向→轻量级→重量级),ReentrantLock 没有锁升级机制
C. synchronized 支持超时获取锁(tryLock 语法),ReentrantLock 不支持
D. ReentrantLock 可选公平锁和非公平锁,synchronized 始终是非公平的
Q5(深入)— 考察场景推理
在某高并发计数器场景中,开发者使用 AtomicInteger 代替 synchronized 来提升性能。但在实际压测中发现,随着并发量的增加,CPU 使用率反而急剧升高,QPS 并未如预期增长。最可能的原因是:
A. AtomicInteger 本身存在线程安全问题,在高并发下会漏计
B. CAS 长时间自旋增加了 CPU 开销,竞争激烈时应升级为重量级锁或使用其他方案
C. AtomicInteger 的 value 字段缺少 volatile 修饰,线程间看不到最新值
D. AtomicInteger 的 incrementAndGet() 不是原子操作
Q6(深入)— 考察源码级理解
AQS 的 CLH 队列中,当一个节点的状态为 SIGNAL 时,意味着什么?
A. 该线程已取消等待(CANCELLED)
B. 该线程的后继节点需要被 unpark(即前驱释放锁后会唤醒后继)
C. 该线程正在等待条件变量(CONDITION)
D. 该节点处于共享模式传播状态(PROPAGATE)
二、填空题(3道)
F1 — 填空1
在轻量级锁的获取流程中,竞争发生时线程会进行自旋重试。如果自旋超过阈值(默认 (1) 次,可通过 -XX:PreBlockSpin 调整),就会升级为__(2)锁。此时未获得锁的线程会被(3)__挂起,进入 OS 的等待队列,需要切换到内核态,这是性能损耗最大的环节。
提示: 回忆轻量级锁的自旋阈值和重量级锁的关键特征。
F2 — 填空2
CAS 是 CPU 级别的原语指令,在 x86 架构下对应__(1)汇编指令。在多核环境下通过总线锁或缓存锁保证原子性。CAS 的一个经典问题是(2)问题——线程 T1 读取值为 A,T2 把值改为 B 再改回 A,T1 的 CAS 检查时发现值仍是 A 但实际值已经被修改过。解决思路是给值加(3)__,每次变更版本号加 1。
提示: x86 的 cmpxchg 指令是 CAS 的硬件基础,ABA 的解法是加版本戳。
F3 — 填空3
AQS 的核心是一个 volatile int state 变量。在不同同步器中,state 的含义不同:ReentrantLock 中 state 表示__(1);CountDownLatch 中 state 表示(2)(递减到 0 后触发);Semaphore 中 state 表示(3)__。
提示: state 的含义取决于具体实现类的语义,回忆文中 AQS 状态机表格。
三、简答题(1道)
S1
某电商秒杀系统在订单扣减环节面临高并发竞争。开发团队最初使用 synchronized 保护库存扣减逻辑,后发现性能瓶颈。团队计划迁移到 ReentrantLock + AQS 的方案。已知以下条件:
- 峰值 QPS 约 5000
- 库存扣减需要保证原子性和一致性
- 部分上游服务依赖超时较短(200ms),需要支持锁的超时获取
请回答:
- 从 synchronized 迁移到 ReentrantLock 的主要优势有哪些?列出至少 3 个。
- 如果采用 ReentrantLock 的非公平锁模式,请简述其 tryAcquire 的核心逻辑流程(涉及 CAS 和重入)。
- 在 AQS 的 CLH 队列中,如果一个节点的线程已经超时,AQS 如何处理这个节点?节点可能的状态有哪些?
答题框架提示:
- 第 1 问从公平性、中断、超时、Condition 等维度对比
- 第 2 问结合 ReentrantLock tryAcquire 的代码逻辑
- 第 3 问列举 AQS 节点状态及其含义
参考答案与解析
选择题答案
| 题号 | 正确答案 | 解析 |
|---|---|---|
| Q1 | B | synchronized 的锁升级路径是固定的:无锁→偏向锁→轻量级锁→重量级锁。一旦升级到重量级就不会再降级(除非竞争减弱时从退出队列恢复)。 |
| Q2 | B | 偏向锁在实际场景中"永远只有一个人访问"的概率很低,而撤销代价高(需全局 STW),因此 JDK 15 标记废弃、JDK 17 移除。A 错在版本不对,C 错在偏向锁重复获取无需 CAS,D 错在是升级为轻量级而非直接重量级。 |
| Q3 | C | CAS 失败后线程会自旋重试,最多循环指定次数(默认 10 次)。超过阈值才升级为重量级锁。不会立即升或抛异常。 |
| Q4 | C | C 是错误的描述:synchronized 不支持超时获取锁,ReentrantLock 才有 tryLock(timeout)。A、B、D 都是正确的。 |
| Q5 | B | 在高并发竞争下,CAS 自旋重试会消耗大量 CPU,这就是为什么有界锁最终会升级为重量级锁。QPS 不上涨是因为 CPU 变成了瓶颈。 |
| Q6 | B | SIGNAL 状态表示该节点的后继节点需要被 unpark——即前驱释放锁后会唤醒后继。CANCELLED=已取消,CONDITION=等待条件变量,PROPAGATE=共享模式传播。 |
填空题答案
| 题号 | 答案 | 解析 |
|---|---|---|
| F1 | (1)10 (2)重量级 (3)阻塞 | 轻量级锁自旋阈值为 10 次,超时会退化为重量级锁。重量级锁通过 Monitor 实现,线程阻塞挂起需要内核态切换。 |
| F2 | (1)cmpxchg (2)ABA (3)版本号 | cmpxchg 是 x86 的 CAS 汇编指令。ABA 问题的解法是 AtomicStampedReference ——给值加版本号。 |
| F3 | (1)持有锁的次数(重入计数) (2)计数器初始值 (3)可用许可证数量 | state 的含义因同步器而异,但其声明始终是 volatile int,保证可见性。 |
简答题参考答案
S1:参考答案要点:
- 主要优势:① 支持公平锁/非公平锁可选,可以根据业务选择合适的策略;② 支持
lockInterruptibly()响应中断,避免因某个锁永远拿不到而导致线程无限阻塞;③ 支持tryLock(timeout)超时获取,满足上游 200ms 超时约束;④ 支持多个 Condition 变量,比 synchronized 的 wait()/notify() 更灵活。 - 非公平锁 tryAcquire 核心流程:① 先尝试直接用 CAS 拿锁(
compareAndSetState(0, acquires)),成功则设置独占线程;② 如果 state 不为 0,判断当前线程是否为已有的独占线程,如果是则重入累加 state;③ 都不满足则返回 false,走 AQS 排队流程。 - AQS 节点可能的状态包括:
CANCELLED(值为 1,已取消等待)、SIGNAL(值为 -1,后继需 unpark)、CONDITION(值为 -2,等待条件变量)、PROPAGATE(值为 -3,共享模式传播)。如果节点超时,通常会将其状态设为 CANCELLED 并从队列中移除(由前驱节点的 unlinkCancelledNodes 或 self-unpark 机制处理)。
评分标准:答出任意 2 个要点即可得满分;完全正确需覆盖全部要点。