【2025面试常问Java八股】AQS介绍(AbstractQueuedSynchronizer 抽象队列同步器)

发布于:2025-04-21 ⋅ 阅读:(20) ⋅ 点赞:(0)

经典回答

"AbstractQueuedSynchronizer(AQS)是Java并发包的核心框架,为构建锁和同步器提供了底层支持。像ReentrantLock、Semaphore这些常用并发工具都是基于AQS实现的。它的核心思想是通过一个int类型的state变量表示同步状态,配合CLH队列管理线程的排队与唤醒。"

"AQS使用volatile修饰的state变量表示同步状态,通过CAS操作保证原子性修改。比如ReentrantLock用它记录重入次数,Semaphore用它表示剩余许可数。"

"采用CLH变体的FIFO双向队列管理等待线程。每个线程被封装成Node节点,通过waitStatus标识线程状态(如CANCELLED、SIGNAL)。"

AQS中的阻塞队列是一个CLH队列。CLH(Craig, Landin, and Hagersten)队列是一种用于实现自旋锁的有效数据结构。它是由Craig, Landin和Hagersten首次提出的,因此得名。

"AQS采用模板方法模式,定义了acquire/release等骨架方法,而将tryAcquire/tryRelease等具体操作交给子类实现,这种设计非常优雅。"

"可以把AQS想象成游乐园的排队系统:游客(线程)先尝试直接进入(tryAcquire)如果满员(获取失败),就去排队区(CLH队列)取号等待当前游客离开(release)时,系统通知下一位游客(unpark)共享模式就像团体票,可以一次性放行多人"

高性能:通过自旋+CAS减少阻塞

灵活性:支持独占/共享两种模式

可扩展:基于模板方法方便实现各种同步器

公平可选:支持公平与非公平策略

"在JUC包中有很多经典实现:

ReentrantLock:可重入独占锁

CountDownLatch:倒计时门闩

Semaphore:信号量控制

ThreadPoolExecutor.Worker:线程池工作线程控制

比如ReentrantLock的公平锁实现,就是在tryAcquire中先检查hasQueuedPredecessors()确保先来先服务。"

"理解AQS的设计,不仅能帮助我们更好地使用JUC工具,当需要实现特定需求的同步器时,也能基于AQS快速开发。"

AQS源码

public abstract class AbstractQueuedSynchronizer

extends AbstractOwnableSynchronizer

implements java.io.Serializable {

}

Java AQS (AbstractQueuedSynchronizer) 深度解析

AQS 是 Java 并发包的核心基础框架,为构建锁和同步器提供了底层支持。理解 AQS 是掌握 Java 并发编程的关键。

一、AQS 核心概念

1. 基本定位

  • 全称:AbstractQueuedSynchronizer

  • 位置java.util.concurrent.locks 包

  • 作用:构建锁和同步器的框架(如 ReentrantLock、CountDownLatch 等)

2. 核心思想

  • CLH 队列:基于 FIFO 等待队列的变种

  • 状态管理:通过单个原子 int 值表示同步状态

  • 模板模式:需要子类实现特定方法

二、核心数据结构

1. 同步状态

private volatile int state; // 关键状态变量

2. 等待队列节点

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

3. 等待状态值

常量名 含义
1 CANCELLED 线程已取消
-1 SIGNAL 后继线程需要唤醒
-2 CONDITION 在条件队列中等待
-3 PROPAGATE 共享模式下传播唤醒

三、工作原理解析

1. 独占模式(如 ReentrantLock)

2. 共享模式(如 Semaphore)

四、关键方法解析

1. 需要子类实现的方法

方法 说明
tryAcquire(int) 尝试获取独占锁
tryRelease(int) 尝试释放独占锁
tryAcquireShared(int) 尝试获取共享锁
tryReleaseShared(int) 尝试释放共享锁
isHeldExclusively() 是否被当前线程独占

2. 重要模板方法

方法 说明
acquire(int) 独占式获取锁
acquireInterruptibly(int) 可中断获取
tryAcquireNanos(int, long) 带超时获取
release(int) 独占式释放
acquireShared(int) 共享式获取
releaseShared(int) 共享式释放

五、AQS 在 JUC 中的应用

1. ReentrantLock

final Sync extends AbstractQueuedSynchronizer {
    // 实现tryAcquire/tryRelease
    protected final boolean tryAcquire(int acquires) {
        Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            setState(c + acquires); // 可重入
            return true;
        }
        return false;
    }
}

2. CountDownLatch

private static final class Sync extends AbstractQueuedSynchronizer {
    Sync(int count) { setState(count); }
    
    protected int tryAcquireShared(int acquires) {
        return (getState() == 0) ? 1 : -1;
    }
    
    protected boolean tryReleaseShared(int releases) {
        // 自旋减少状态值
        for (;;) {
            int c = getState();
            if (c == 0) return false;
            int nextc = c-1;
            if (compareAndSetState(c, nextc))
                return nextc == 0;
        }
    }
}

六、AQS 设计精髓

1. 性能优化点

  • CAS 操作:状态变更使用 compareAndSetState

  • 自旋检查:入队前多次尝试获取锁

  • 头节点检查:只有前驱是头节点才尝试获取

2. 公平性实现

// 公平锁实现示例
protected final boolean tryAcquire(int acquires) {
    if (!hasQueuedPredecessors() && // 检查是否有排队线程
        compareAndSetState(0, acquires)) {
        setExclusiveOwnerThread(current);
        return true;
    }
    // ...
}

3. 条件变量支持

public class ConditionObject implements Condition {
    private transient Node firstWaiter; // 条件队列头
    private transient Node lastWaiter;  // 条件队列尾
    
    public final void await() throws InterruptedException {
        Node node = addConditionWaiter();
        int savedState = fullyRelease(node);
        // ...
    }
}

七、AQS 使用示例

自定义互斥锁

class Mutex implements Lock {
    private final Sync sync = new Sync();
    
    static class Sync extends AbstractQueuedSynchronizer {
        protected boolean tryAcquire(int ignore) {
            return compareAndSetState(0, 1);
        }
        
        protected boolean tryRelease(int ignore) {
            setState(0);
            return true;
        }
    }
    
    public void lock() { sync.acquire(1); }
    public void unlock() { sync.release(1); }
    // 其他方法实现...
}

AQS 通过精妙的设计,将同步器的通用逻辑抽象出来,让开发者只需关注特定同步策略的实现。理解 AQS 的工作机制,不仅能帮助更好地使用 JUC 中的工具类,也能为设计自定义同步组件提供坚实基础。


网站公告

今日签到

点亮在社区的每一天
去签到