1. AQS 源码面试三板斧:从"用过"到"懂过"的关键跨越
在 Java 并发编程面试中,AbstractQueuedSynchronizer(AQS)就像一道分水岭。我见过太多候选人能背出"AQS 是构建锁和同步器的基础框架"这样的定义,却在面试官追问三行源码时突然语塞。今天我们就直击要害,拆解面试官最常考察的三段 AQS 源码,让你从"听说过"跃升到"真懂过"。
1.1 state 字段:并发世界的原子裁判
java复制public abstract class AbstractQueuedSynchronizer {
private volatile int state;
protected final int getState() {
return state;
}
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
}
这段代码看似简单,却藏着三个面试必考点:
-
volatile 的双重作用:不仅保证可见性,更重要的是防止指令重排序。在 AQS 中,state 的修改必须对其他线程立即可见,否则会导致锁状态不一致。
-
CAS 操作的深层含义:compareAndSetState 不是简单的 setter,而是整个 AQS 的基石。它实现了无锁化的状态变更,这才是 AQS 高性能的关键。
-
state 的哲学意义:这个 int 变量不是锁,而是"资格凭证"。比如在 ReentrantLock 中,state=0 表示空闲,state=1 表示被占用,state>1 表示重入次数。
面试陷阱:当面试官问"state 代表什么?"时,平庸的回答是"表示锁的状态",而高手会说:"state 是同步状态的抽象表示,具体语义由子类定义。比如在 Semaphore 中它表示剩余许可数,在 CountDownLatch 中表示剩余计数。"
1.2 acquire 方法:一次机会的公平博弈
java复制public final void acquire(int arg) {
if (!tryAcquire(arg)) {
Node node = addWaiter(Node.EXCLUSIVE);
acquireQueued(node, arg);
}
}
这段代码揭示了 AQS 最精妙的设计哲学:
-
tryAcquire 的战术地位:这是模板方法模式的应用,子类必须实现自己的获取逻辑。但关键在于它只有一次尝试机会,失败立即进入排队流程。
-
非公平锁的本质:新线程总是先尝试获取锁(tryAcquire),失败才排队。这意味着新线程有机会"插队",这就是非公平锁的实现原理。
-
addWaiter 的细节:Node.EXCLUSIVE 表示独占模式,对应的还有 SHARED 模式。这里创建的 Node 会包含当前线程信息,并通过 CAS 操作快速入队。
避坑指南:很多面试者说不清为什么要有 tryAcquire 这步直接尝试。其实这是为了减少线程切换开销——如果锁刚好可用,就不必经历昂贵的挂起/唤醒过程。
1.3 release 方法:责任重大的交接仪式
java复制public final boolean release(int arg) {
if (t
