欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > 什么是AQS

什么是AQS

2025/6/23 6:17:50 来源:https://blog.csdn.net/2401_87189717/article/details/148810384  浏览:    关键词:什么是AQS

面试资料大全|各种技术资料-2000G

一、AQS 本质与定位

AQS(AbstractQueuedSynchronizer) 是 Java 并发包(java.util.concurrent.locks)的核心框架,它为实现阻塞锁同步器提供了底层支持。作为 Java 并发编程的基石,AQS 被广泛应用于 JUC(Java Util Concurrent)中:

classDiagramAbstractQueuedSynchronizer <|-- ReentrantLock$SyncAbstractQueuedSynchronizer <|-- Semaphore$SyncAbstractQueuedSynchronizer <|-- CountDownLatch$SyncAbstractQueuedSynchronizer <|-- ReentrantReadWriteLock$SyncReentrantLock$Sync <|-- NonfairSyncReentrantLock$Sync <|-- FairSync

核心价值:AQS 解决了同步器的排队机制线程阻塞/唤醒等通用问题,让开发者只需关注状态管理逻辑

二、AQS 核心设计思想

1. 三大核心组件

组件作用实现方式
状态变量 (state)同步状态(如锁的重入次数、信号量许可数)volatile int + CAS 操作
CLH 队列存储等待线程的 FIFO 队列双向链表(Node 节点)
模板方法供子类实现的获取/释放逻辑tryAcquire()/tryRelease() 等方法

2. CLH 队列原理

Head
Thread Node 1
Thread Node 2
Thread Node 3
Tail

节点结构

static final class Node {volatile int waitStatus;    // 等待状态volatile Node prev;         // 前驱节点volatile Node next;         // 后继节点volatile Thread thread;     // 等待线程Node nextWaiter;            // 条件队列专用
}

等待状态值

  • CANCELLED (1):线程已取消
  • SIGNAL (-1):后继线程需要被唤醒
  • CONDITION (-2):线程在条件队列等待
  • PROPAGATE (-3):共享模式下状态需要传播

三、AQS 工作原理

1. 独占模式获取锁(acquire)

public final void acquire(int arg) {if (!tryAcquire(arg) &&          // 子类实现获取逻辑acquireQueued(               // 加入等待队列addWaiter(Node.EXCLUSIVE), arg)) // 创建独占节点selfInterrupt();             // 恢复中断状态
}

2. 节点入队流程

Thread AQS 调用acquire(arg) tryAcquire(arg) 失败 创建Node(EXCLUSIVE) 尝试快速入队(CAS设置tail) 返回节点 enq(node) 自旋入队 alt [CAS成功] [CAS失败] acquireQueued(node,arg) 阻塞线程 Thread AQS

四、AQS 的两种模式

1. 独占模式(Exclusive)

  • 特点:同一时刻只有一个线程能获取资源
  • 应用ReentrantLock
  • 核心方法
    protected boolean tryAcquire(int arg) // 子类实现
    protected boolean tryRelease(int arg) // 子类实现
    

2. 共享模式(Shared)

  • 特点:多个线程可同时获取资源
  • 应用Semaphore, CountDownLatch
  • 核心方法
    protected int tryAcquireShared(int arg) // 子类实现
    protected boolean tryReleaseShared(int arg) // 子类实现
    

五、AQS 在同步器中的实现

1. ReentrantLock 实现

// 非公平锁获取
final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (compareAndSetState(0, acquires)) { // CAS抢锁setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) { // 重入逻辑setState(c + acquires);return true;}return false;
}

2. Semaphore 实现

protected int tryAcquireShared(int acquires) {for (;;) {int available = getState();int remaining = available - acquires;if (remaining < 0 || compareAndSetState(available, remaining)) // CAS扣减许可return remaining;}
}

六、AQS 的四大关键技术

1. CAS(Compare-And-Swap)

// 原子更新状态
protected final boolean compareAndSetState(int expect, int update) {return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

2. LockSupport 线程控制

// 阻塞当前线程
LockSupport.park(this);// 唤醒指定线程
LockSupport.unpark(thread);

3. 自旋优化

for (;;) { // 自旋避免直接阻塞if (canAcquire) break;// 短暂自旋后进入阻塞
}

4. 队列管理算法

  • 入队:CAS设置尾节点
  • 出队:设置头节点并唤醒后继
  • 取消:清理CANCELLED节点

七、AQS 的高级特性

1. 条件变量(ConditionObject)

public class ConditionObject implements Condition {public final void await() {Node node = addConditionWaiter(); // 加入条件队列int savedState = fullyRelease(node);while (!isOnSyncQueue(node)) {LockSupport.park(this);       // 阻塞}acquireQueued(node, savedState);  // 重新竞争锁}
}

2. 公平 vs 非公平策略

策略实现原理优点缺点
非公平锁新线程直接 CAS 抢锁高吞吐量可能线程饥饿
公平锁检查队列是否有等待线程才尝试获取保证顺序性上下文切换多

八、为什么需要 AQS

传统同步的局限性

// synchronized 不足:
// 1. 无法中断等待
// 2. 单一等待队列
// 3. 无法实现复杂策略// wait/notify 不足:
// 1. 必须配合synchronized使用
// 2. 通知是广播式的

AQS 的优势

  1. 灵活性:支持尝试获取、超时获取、可中断获取
  2. 扩展性:通过继承实现自定义同步器
  3. 高性能:CAS + CLH队列减少竞争
  4. 功能性:支持多个条件变量

九、AQS 的最佳实践

自定义同步器示例

class SimpleLock extends AbstractQueuedSynchronizer {// 尝试获取锁protected boolean tryAcquire(int acquires) {if (compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}// 尝试释放锁protected boolean tryRelease(int releases) {if (getState() == 0) throw new IllegalMonitorStateException();setExclusiveOwnerThread(null);setState(0);return true;}// 创建锁接口public void lock() { acquire(1); }public void unlock() { release(1); }
}

使用注意事项

  1. 状态管理

    // 正确使用原子操作
    compareAndSetState(oldState, newState);// 错误:直接修改状态
    setState(newState); // 非线程安全!
    
  2. 避免死锁

    lock.lock();
    try {// 临界区代码
    } finally {lock.unlock(); // 必须确保释放
    }
    

面试资料大全|各种技术资料-2000G

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词