aqs中独占模式与共享模式本质是两种资源访问契约:独占模式一次仅允许一个线程持有资源,对应排他语义,核心方法为tryacquire/tryrelease,state表持有状态,唤醒仅一个后继;共享模式允许多线程并发获取,对应协作语义,核心方法为tryacquireshared/tryreleaseshared,state表剩余资源数,释放时传播唤醒多个后继。

AQS 中的独占模式和共享模式,本质是两种不同的资源访问契约,不是语法层面的开关,而是由子类实现哪组方法、以及如何解释 state 值共同决定的。
独占模式:一次只让一个线程进临界区
它对应“排他性”语义:资源在同一时刻只能被一个线程持有。典型如 ReentrantLock、ReentrantReadWriteLock 的写锁。
- 核心方法是
tryAcquire(int arg)和tryRelease(int arg)—— 返回true表示抢锁成功,false则入队等待 -
state通常表示锁的持有状态:0 代表无锁,1 代表已被占用;可重入锁还会用它记录重入次数 - 释放锁时调用
unparkSuccessor,只唤醒同步队列中排在最前面的**一个**有效后继节点 - 节点在队列中用
nextWaiter == null标识为独占模式(Node.EXCLUSIVE)
共享模式:允许多个线程同时通行
它对应“协作性”语义:多个线程可并发获取资源,只要条件满足。典型如 Semaphore、CountDownLatch、读写锁的读锁。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 核心方法是
tryAcquireShared(int arg)和tryReleaseShared(int arg) -
tryAcquireShared返回值有明确含义:负数(失败)、0(成功但不唤醒后续)、正数(成功且需传播唤醒) -
state通常表示可用资源数,比如许可数量或倒计时剩余值 - 释放时调用
doReleaseShared,会循环尝试唤醒后续所有能成功的共享节点,直到遇到失败或队列尾 - 节点用
nextWaiter == Node.SHARED标识为共享模式
关键区别不只是“能不能多人用”,更在行为契约上
两种模式共用同一套 FIFO 同步队列,但唤醒逻辑、状态语义、节点标记完全不同,不能混用。
- 唤醒粒度不同:独占只唤醒一个;共享可能连续唤醒多个
- state 解释不同:独占侧重“是否被占”,共享侧重“还剩多少”
- 返回值语义不同:独占是布尔逻辑;共享是带传播意图的整数信号
- 子类不应在一个同步器里同时支持两种模式,除非像
ReentrantReadWriteLock那样通过不同 API 明确隔离读/写路径
选哪种模式,取决于你要建的同步器想表达什么
如果资源必须互斥访问(比如修改共享变量),就走独占;如果只是协调多个线程对某类资源的配额使用(比如限制并发请求数),就用共享。
写自定义同步器时,选错模式或返回值含义不对,轻则功能失效,重则导致死锁或 CPU 空转。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










