洛阳市网站建设_网站建设公司_Photoshop_seo优化
2026/1/18 6:20:01 网站建设 项目流程

🔑 一、AQS 是什么?——“同步器的骨架”

AQS = AbstractQueuedSynchronizer
它是一个抽象类,提供了一套基于 FIFO 阻塞队列 + 原子状态管理的框架,让你能轻松实现各种自定义的同步工具。

✅ 核心能力:

  1. 管理一个整型状态(state:表示资源是否可用(如锁是否被占用、计数器剩余值等)。
  2. 维护一个 FIFO 等待队列:当线程获取资源失败时,自动入队并阻塞;释放资源时,唤醒队列中的下一个线程。
  3. 支持独占模式(exclusive)和共享模式(shared)
    • 独占:同一时刻只能一个线程持有(如ReentrantLock)。
    • 共享:多个线程可同时持有(如SemaphoreCountDownLatch)。

💡AQS 本身不定义“同步语义”,而是把“如何判断能否获取资源”、“如何释放资源”这些逻辑留给子类实现


🧱 二、AQS 的核心机制

1.状态管理(State)

  • 通过volatile int state表示同步状态。
  • 提供三个方法操作它:
    protectedfinalintgetState()protectedfinalvoidsetState(intnewState)protectedfinalbooleancompareAndSetState(intexpect,intupdate)// CAS
  • 子类通过这个state来表达自己的业务含义:
    • ReentrantLock:0=未锁,1=已锁(重入次数)
    • Semaphore:表示剩余许可数量
    • CountDownLatch:表示倒计数值

2.FIFO 等待队列(CLH 变种)

AQS 使用一个双向链表(Node 链表)来管理等待线程:

head → [Node1] ↔ [Node2] ↔ [Node3] ← tail

每个Node包含:

  • thread:等待的线程
  • waitStatus:节点状态(如SIGNAL=-1表示需要被唤醒)
  • prev/next:前后指针
  • nextWaiter:用于区分是独占还是共享模式(或用于 Condition)

⚠️ 注意:这是一个CLH 队列的变种,原始 CLH 用于自旋锁,而 AQS 用于阻塞锁,所以增加了next指针便于唤醒后继。


3.两种模式:独占 vs 共享

模式方法说明
独占(Exclusive)tryAcquire()
tryRelease()
成功则获得排他权限(如写锁)
共享(Shared)tryAcquireShared()
tryReleaseShared()
返回值 ≥0 表示成功,可多线程并发(如读锁、信号量)

🔄 共享模式下,释放资源时可能级联唤醒多个线程(因为多个线程可能同时满足条件)。


🧩 三、关键流程解析

▶ 获取资源(以独占为例)

publicfinalvoidacquire(intarg){if(!tryAcquire(arg)&&acquireQueued(addWaiter(Node.EXCLUSIVE),arg))selfInterrupt();}
  1. 先尝试tryAcquire()(由子类实现)。
  2. 如果失败,调用addWaiter()将当前线程封装成Node加入队尾。
  3. 调用acquireQueued():在队列中自旋,直到被前驱唤醒且自己成为头节点后再次尝试获取。

▶ 释放资源(独占)

publicfinalbooleanrelease(intarg){if(tryRelease(arg)){// 子类实现Nodeh=head;if(h!=null&&h.waitStatus!=0)unparkSuccessor(h);// 唤醒后继returntrue;}returnfalse;}
  • 成功释放后,调用unparkSuccessor()唤醒下一个等待线程。

🔍unparkSuccessor()会从tail往前找第一个非取消的节点(处理中间节点被中断/超时的情况)。


🛠️ 四、如何使用 AQS?——子类必须实现的方法

不能直接使用 AQS,而是继承它并实现以下方法(根据需求选):

方法用途必须实现?
tryAcquire(int)独占式获取是(如果支持独占)
tryRelease(int)独占式释放
tryAcquireShared(int)共享式获取是(如果支持共享)
tryReleaseShared(int)共享式释放
isHeldExclusively()当前线程是否独占持有是(如果要用Condition

✅ 所有这些方法都必须是无阻塞、线程安全、短小精悍的!


📌 五、经典例子回顾

例1:非重入互斥锁(Mutex)

staticclassSyncextendsAbstractQueuedSynchronizer{protectedbooleantryAcquire(intacquires){if(compareAndSetState(0,1)){setExclusiveOwnerThread(Thread.currentThread());returntrue;}returnfalse;}protectedbooleantryRelease(intreleases){setState(0);setExclusiveOwnerThread(null);returntrue;}protectedbooleanisHeldExclusively(){returngetState()==1;}}

例2:一次性门闩(BooleanLatch)

staticclassSyncextendsAbstractQueuedSynchronizer{protectedinttryAcquireShared(intignore){returngetState()==1?1:-1;// 1=已触发,-1=需等待}protectedbooleantryReleaseShared(intignore){setState(1);returntrue;// 唤醒所有等待者}}

🌟 六、高级特性

1.公平性控制

  • 默认是非公平的(允许“插队”:新线程可能在排队线程之前抢到锁)。
  • 实现公平锁:在tryAcquire中加判断:
    if(hasQueuedPredecessors())returnfalse;// 有排队者就别插队

2.Condition 支持

  • 通过new ConditionObject()创建条件变量。
  • 必须实现isHeldExclusively()和正确的release/acquire逻辑。

3.可中断、超时支持

  • AQS 提供了acquireInterruptiblytryAcquireNanos等方法,子类只需调用即可。

✅ 总结:AQS 的设计哲学

“Don’t call us, we’ll call you.” — Hollywood Principle

  • AQS 负责:队列管理、线程阻塞/唤醒、状态原子性、中断/超时处理
  • 你(子类)负责:定义“什么是获取成功”、“什么是释放成功”

这使得你可以用几十行代码实现出工业级的同步器,而无需操心底层并发细节。


如果你正在学习 JUC 或想深入理解ReentrantLockSemaphore等的原理,掌握 AQS 是必经之路。它的设计堪称 Java 并发编程的“皇冠上的明珠”。

如需进一步分析某个具体同步器(比如ReentrantReadWriteLock如何用 AQS 实现读写锁),欢迎继续提问!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询