aqs中独占锁与共享锁的核心差异在于“谁可以进”“谁被唤醒”及“唤醒后怎么做”:独占锁同一时刻仅一个线程持有,释放后只唤醒队列首节点;共享锁允许多线程同时持有,释放后通过doreleaseshared()循环唤醒后续共享节点并传播。

AQS 中的独占锁和共享锁,获取与释放的核心差异不在队列结构,而在于“谁可以进”“谁被唤醒”以及“唤醒后怎么做”。两者共用同一个 FIFO 同步队列,但行为逻辑完全不同。
独占锁的获取与释放
典型代表是 ReentrantLock。它保证同一时刻只有一个线程持有锁。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
获取(acquire):调用
acquire(int arg)→ 先执行tryAcquire(arg)。该方法由子类实现,返回 true 表示成功(比如检查 state 是否为 0 或当前线程已持有),false 则将线程封装为Node.EXCLUSIVE节点入队,并挂起等待 -
释放(release):调用
release(int arg)→ 执行tryRelease(arg)。若返回 true,说明锁真正释放了(如 state 减至 0),AQS 会调用unparkSuccessor(head),只唤醒队列中第一个有效后继节点(即离 head 最近的非 CANCELLED 节点) - 注意:
tryAcquire必须快速返回,不能阻塞;重入逻辑(如判断当前线程是否已持锁)必须由子类自己处理,AQS 不介入
共享锁的获取与释放
典型代表是 Semaphore、CountDownLatch、ReentrantReadWriteLock.ReadLock。允许多个线程同时持有锁(读锁)或按配额并发访问(信号量)。
-
获取(acquireShared):调用
acquireShared(int arg)→ 执行tryAcquireShared(arg)。该方法返回值有明确语义:
• 负数:失败,入队等待
• 0:成功,但不传播唤醒(后续节点不会被主动唤醒)
• 正数:成功,且应继续唤醒后继共享节点(触发传播链) -
释放(releaseShared):调用
releaseShared(int arg)→ 执行tryReleaseShared(arg)。若返回 true,表示释放后可能允许更多线程获取,则 AQS 调用doReleaseShared()—— 它会循环尝试唤醒头节点后的共享节点,并设置头节点、继续传播,直到遇到非共享节点或返回值不再满足条件 - 关键细节:共享节点入队时使用
Node.SHARED标记(通过nextWaiter == SHARED判断),AQS 靠这个区分模式,不是靠队列位置
两种模式共用但行为分离的关键点
虽然都走同一套队列管理逻辑,但唤醒机制完全解耦:
- 独占模式释放后只唤醒一个,适合互斥场景;共享模式释放后可能唤醒多个,适合“资源够就一起上”的场景
- 共享模式下,
tryAcquireShared返回 0 是常见陷阱——看似成功,实则中断传播,导致后续等待线程永远沉睡 - ReentrantReadWriteLock 是混合体:写锁走独占流程,读锁走共享流程,state 的高低 16 位分别记录读/写状态,但 Sync 类统一调度两种模式
- 所有模式都依赖
state的 CAS 修改(compareAndSetState)来保障原子性,子类决定 state 的业务含义(如重入次数、许可数量、读写计数)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










