Lock接口仅支持独占模式,其方法设计严格遵循“一次仅一个线程持有”语义;共享模式由ReadWriteLock、Semaphore等独立接口或同步器实现,AQS通过tryAcquire/tryRelease与tryAcquireShared/releaseShared分别支撑两种模式。

Java 中 AQS 的独占模式与共享模式并不直接体现在 Lock 接口本身,因为 Lock 接口只定义了独占语义的操作(如 lock()、unlock()、tryLock()),它天然对应 AQS 的独占模式。共享模式的语义无法通过 Lock 接口表达,而是由其他接口(如 ReadWriteLock)或具体同步器(如 CountDownLatch、Semaphore)承载。
Lock 接口只支持独占语义
Lock 接口的方法签名和行为设计完全围绕「一次仅一个线程持有」展开:
-
lock()阻塞获取,成功即获得唯一访问权 -
tryLock()非阻塞尝试,返回true表示独占成功 -
unlock()释放后仅唤醒队列头部的一个等待线程(unparkSuccessor) - 所有实现类(如
ReentrantLock)内部都使用AQS.tryAcquire/tryRelease,返回布尔值,不涉及传播逻辑
共享语义需绕过 Lock 接口另行实现
当需要多个线程同时进入时,Java 并不会扩展 Lock 接口来支持共享,而是提供独立的抽象:
-
ReadWriteLock接口分离读锁与写锁:其readLock()返回的Lock实例实际是共享语义的封装(底层调用AQS.acquireShared),但对外仍实现Lock接口——这是语义伪装,不是真正兼容 -
CountDownLatch、Semaphore、CyclicBarrier等不实现Lock,而是直接基于 AQS 的共享模式构建,使用tryAcquireShared和releaseShared - 任何试图让一个
Lock实例支持共享行为的做法,都会破坏接口契约,导致调用方误判(例如isHeldByCurrentThread()在读锁场景下失去意义)
ReadWriteLock 是关键桥梁
ReentrantReadWriteLock 是唯一将独占与共享共存于同一 AQS 实例的典型:
立即学习“Java免费学习笔记(深入)”;
- 写锁(
writeLock())走独占路径:tryAcquire→ 修改低 16 位 state - 读锁(
readLock())走共享路径:tryAcquireShared→ 检查高 16 位并尝试 CAS 增加 - 两者共享同一队列,靠
Node的nextWaiter == Node.SHARED区分等待类型,唤醒时分别处理 - 但注意:
readLock()返回的Lock对象只是外观层包装,其lock()方法内部调用的是acquireShared(1),而非标准独占流程
设计意图清晰:接口职责单一
AQS 的双模式与 Java 并发接口体系是解耦设计的体现:
-
Lock接口专注「互斥控制」,对应现实中的「排他性资源」(如账户余额修改) - 共享需求被归入更上层的语义模型:
ReadWriteLock(读写分离)、Semaphore(许可池)、CountDownLatch(到达门闩) - 这种分离避免了接口膨胀,也防止使用者混淆「能否并发」这一根本语义差异


















