独占式同步器通过state变量实现排他性控制,仅允许一个线程持有资源;共享式同步器以state表示剩余许可数,支持多线程并发访问;state操作必须用CAS保证原子性与可见性;推荐用private static final内部类封装AQS子类。

独占式同步器:一次只允许一个线程进入
独占模式的核心是“排他性”——同一时刻仅一个线程能持有资源。AQS 用 state 变量表示锁状态,通常初始化为 0(空闲),线程获取成功后设为 1(占用)。关键在于子类必须重写 tryAcquire(int) 和 tryRelease(int) 方法:
- tryAcquire:检查 state 是否为 0;若是,用 CAS 将其设为 1,返回 true;否则返回 false,触发排队逻辑
- tryRelease:将 state 从 1 设回 0,返回 true;若失败(比如未持有锁却调用释放),应返回 false
- 可重入支持需在 tryAcquire 中判断当前线程是否已持有锁,是则 state +1;tryRelease 则需递减,直到 state 归零才真正释放
共享式同步器:允许多个线程按配额并发访问
共享模式适用于有容量限制的资源池,如信号量、多窗口银行服务。state 不再是二值开关,而是表示“剩余可用许可数”。子类需重写 tryAcquireShared(int) 和 tryReleaseShared(int):
- tryAcquireShared:尝试用 CAS 减少 state;若结果 ≥ 0,说明获取成功,返回该值(正数表示仍有余量);负数表示失败
- tryReleaseShared:用 CAS 增加 state;成功后返回 true,通知 AQS 唤醒等待中的共享线程
- 注意返回值语义:AQS 根据返回值正负决定是否唤醒后续节点,不是简单的布尔值
state 操作必须原子且可见
AQS 的 state 是 volatile int,保证线程间可见性,但不保证复合操作原子性。因此所有读-改-写都必须依赖 CAS:
- 直接用 setState 仅适用于已知无竞争的场景(如初始化或内部状态重置)
- 常规增减操作一律使用 compareAndSetState(expect, update),例如:先读 getState(),再 CAS 更新,失败则重试
- 避免在 tryAcquire 中写成 “if (state == 0) setState(1)” —— 这存在竞态漏洞
模板结构:推荐用静态内部类封装 AQS 子类
官方实践建议将 AQS 子类声明为自定义同步器的 private static final 内部类,好处明确:
- 对外隐藏同步器实现细节,只暴露 clean 的 API(如 lock()/unlock() 或 acquire()/release())
- 避免 this 引用逃逸,防止子类构造过程中被外部误用
- 代理逻辑清晰:同步器的 public 方法只需调用内部 AQS 实例对应方法,如 this.sync.tryAcquire(1)

















