aqs通过模板方法模式实现同步机制,acquire为固定骨架,子类必须重写tryacquire等钩子方法来定义锁获取逻辑,确保语义清晰、状态原子更新且不阻塞。

AbstractQueuedSynchronizer(AQS)的 tryAcquire 是一个由子类决定具体行为的模板方法,它不直接实现加锁逻辑,而是把“是否能获取锁、如何更新状态”这些关键决策权交给子类。 这正是模板方法模式的典型应用:父类定义算法骨架(如 acquire 流程),子类通过重写 tryAcquire 等钩子方法来定制核心步骤。
tryAcquire 是 AQS 加锁流程中的关键钩子
AQS 的 acquire(int arg) 方法是公共入口,它内部按固定顺序执行:先调用 tryAcquire(arg) 尝试获取锁;失败则入队、挂起线程。这个 tryAcquire 默认抛出 UnsupportedOperationException,强制子类必须重写——它不是可选逻辑,而是加锁语义的唯一出口。
- 公平锁(
ReentrantLock.FairSync)中,tryAcquire会检查同步队列是否有前驱节点,有则拒绝获取,保证 FIFO - 非公平锁(
ReentrantLock.NonfairSync)中,tryAcquire先 CAS 尝试抢锁,失败再走公平路径 - 读写锁(
ReentrantReadWriteLock.Sync)中,tryAcquire需判断写锁重入、写锁是否被占用、是否允许降级等复杂条件
子类实现 tryAcquire 必须遵守的契约
该方法返回 boolean 值,语义明确:true 表示成功获取同步状态(如获得独占锁),false 表示失败(需排队等待)。它不能阻塞,也不应抛出受检异常。所有状态变更(如修改 state 字段)必须通过原子操作完成,通常使用 compareAndSetState 或 getState/setState 配合 CAS 循环。
- 必须基于当前
state和线程上下文(如Thread.currentThread())做判断 - 若获取成功,必须确保
state更新正确(例如可重入锁要递增 state) - 不能依赖外部锁或阻塞操作,否则破坏 AQS 的非阻塞协作模型
为什么用模板方法而不是策略或回调
AQS 把线程排队、唤醒、中断响应、超时控制等通用机制全部封装在模板中,只开放 tryAcquire、tryRelease、isHeldExclusively 等有限几个方法给子类实现。这种设计既保证了底层同步基础设施的一致性和可靠性,又提供了足够的扩展性。
- 策略模式需要传入不同策略对象,而 AQS 锁对象本身既是同步器又是策略载体,更轻量
- 回调方式难以统一管理状态流转和线程生命周期,AQS 模板能精确控制何时调用、如何恢复
- 所有子类共享同一套 CLH 队列和 park/unpark 机制,避免重复造轮子
实际写子类时的常见误区
初学者容易把业务逻辑或 I/O 操作塞进 tryAcquire,这是危险的。它的职责非常纯粹:仅根据当前状态和参数决定能否立即获取锁,并原子更新状态。
- 不要在其中 sleep、wait、数据库查询或网络调用
- 不要在未成功获取时主动调用
park——那是 AQS 自己做的事 - 注意可重入场景:同一线程多次 acquire 应增加 state,而非简单返回 true
- 如果涉及多种锁模式(如读/写/乐观/悲观),应在
tryAcquire内部做清晰分支,而不是拆成多个 AQS 子类
模板方法在这里不是为了炫技,而是把“同步语义”和“同步机制”解耦——你定义锁怎么用,AQS 负责它怎么稳。










