跳转到内容

AQS原理

来自代码酷
Admin留言 | 贡献2025年5月12日 (一) 00:27的版本 (Page creation by admin bot)

(差异) ←上一版本 | 已核准修订 (差异) | 最后版本 (差异) | 下一版本→ (差异)

AQS(AbstractQueuedSynchronizer)是Java并发编程中构建锁和同步器的核心框架,位于`java.util.concurrent.locks`包下。它为开发者提供了基于FIFO队列的阻塞锁和同步器的实现模板,是理解`ReentrantLock`、`Semaphore`、`CountDownLatch`等工具的基础。

概述[编辑 | 编辑源代码]

AQS通过一个volatile int state变量表示同步状态,并通过内置的FIFO双向队列管理竞争线程的排队工作。其核心思想是:

  • 如果共享资源空闲,线程直接获取资源并修改状态;
  • 如果资源被占用,线程进入队列阻塞等待,直到被前驱节点唤醒。

AQS支持独占模式(如`ReentrantLock`)和共享模式(如`Semaphore`),开发者只需重写`tryAcquire`、`tryRelease`等方法即可实现自定义同步器。

核心结构[编辑 | 编辑源代码]

同步状态(state)[编辑 | 编辑源代码]

通过`volatile int state`表示资源状态,子类通过CAS操作修改它:

  
protected final boolean compareAndSetState(int expect, int update) {  
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);  
}

同步队列[编辑 | 编辑源代码]

使用CLH变体的双向队列管理阻塞线程,节点类型为`Node`:

graph LR A[Head] --> B[Thread1] B --> C[Thread2] C --> D[Tail]

关键方法[编辑 | 编辑源代码]

AQS提供模板方法供子类实现:

  • 独占模式
 * `tryAcquire(int arg)`:尝试获取资源。  
 * `tryRelease(int arg)`:尝试释放资源。  
  • 共享模式
 * `tryAcquireShared(int arg)`:尝试共享获取。  
 * `tryReleaseShared(int arg)`:尝试共享释放。  

代码示例:自定义互斥锁[编辑 | 编辑源代码]

以下是一个基于AQS的简单互斥锁实现:

  
class Mutex extends AbstractQueuedSynchronizer {  
    @Override  
    protected boolean tryAcquire(int arg) {  
        if (compareAndSetState(0, 1)) {  
            setExclusiveOwnerThread(Thread.currentThread());  
            return true;  
        }  
        return false;  
    }  

    @Override  
    protected boolean tryRelease(int arg) {  
        if (getState() == 0) throw new IllegalMonitorStateException();  
        setExclusiveOwnerThread(null);  
        setState(0);  
        return true;  
    }  

    public void lock() { acquire(1); }  
    public void unlock() { release(1); }  
}  

// 使用示例  
public class Main {  
    public static void main(String[] args) {  
        Mutex mutex = new Mutex();  
        new Thread(() -> {  
            mutex.lock();  
            System.out.println("Thread1 acquired lock");  
            mutex.unlock();  
        }).start();  

        new Thread(() -> {  
            mutex.lock();  
            System.out.println("Thread2 acquired lock");  
            mutex.unlock();  
        }).start();  
    }  
}

输出

  
Thread1 acquired lock  
Thread2 acquired lock  

实际应用场景[编辑 | 编辑源代码]

  • `ReentrantLock`:通过AQS实现可重入的独占锁。
  • `Semaphore`:使用AQS管理共享资源的许可数量。
  • `CountDownLatch`:利用AQS同步多个线程的完成状态。

数学原理[编辑 | 编辑源代码]

AQS的队列调度遵循公平性与效率的权衡。设队列长度为n,则:

  • 非公平锁的竞争时间复杂度为O(1)(可能插队)。
  • 公平锁的竞争时间复杂度为O(n)(严格排队)。

总结[编辑 | 编辑源代码]

AQS是Java并发包的基石,其设计精妙之处在于: 1. 通过模板方法模式分离通用逻辑与具体实现。 2. 利用CLH队列减少锁竞争的开销。 3. 支持灵活的自定义同步策略。

理解AQS原理后,可以更高效地使用Java并发工具,并能够根据业务需求设计高性能同步器。