AQS(AbstractQueuedSynchronizer)是 Java 并发包 java.util.concurrent
中的一个非常重要的抽象类,它是许多阻塞队列和同步工具类的基础。AQS 提供了一个框架,使得开发人员可以很容易地构建自己的同步组件。
AQS 的核心概念
-
同步状态:
- AQS 维护了一个名为
state
的 volatile 整型成员变量,用来表示同步状态。 - 这个状态值是所有依赖于 AQS 的同步器共享的数据基础。例如,
ReentrantLock
使用这个状态值来表示锁是否被持有以及被持有了多少次。
- AQS 维护了一个名为
-
等待队列:
- AQS 内部维护了一个 FIFO 等待队列(CLH 锁队列),用于存储那些被阻塞的线程节点。
- 当线程尝试获取同步状态失败时,会被构造成一个节点加入到等待队列中。
- 当同步状态释放时,AQS 会唤醒队列中的下一个节点所代表的线程。
AQS 的工作原理
AQS 的设计基于模板方法模式,它定义了几个核心抽象方法,子类必须实现这些方法以完成特定的同步逻辑。主要包括:
- getState():返回同步状态的当前值。
- setState(int):设置同步状态的值。
- compareAndSetState(int expect, int update):原子地更新同步状态值,如果当前值等于预期值。
除了这些基本方法外,AQS 还定义了以下核心方法供子类使用:
- isHeldExclusively():该方法被子类用来判断当前线程是否独占资源。
- tryAcquire(int) 和 tryRelease(int):这两个方法由子类实现,分别用来尝试获取和释放同步状态。它们决定了同步器的行为。
AQS 的使用示例
-
独占模式:
- 当同步器被一个线程占有时,其他线程无法获取同步状态。例如,
ReentrantLock
和Semaphore
在某些情况下会用到独占模式。 - 在独占模式下,线程需要调用
acquire()
或tryAcquire()
来获取同步状态,调用release()
来释放同步状态。
- 当同步器被一个线程占有时,其他线程无法获取同步状态。例如,
-
共享模式:
- 允许多个线程同时获取同步状态。例如,
Semaphore
和CountDownLatch
可以允许多个线程同时访问共享资源。 - 在共享模式下,线程需要调用
acquireShared()
或tryAcquireShared()
来获取同步状态,调用releaseShared()
来释放同步状态。
- 允许多个线程同时获取同步状态。例如,
AQS 的内部结构
AQS 内部维护了一个双向链表结构的等待队列,其中每个节点代表一个等待获取同步状态的线程。当线程获取同步状态失败时,就会被构造成一个节点加入到等待队列的尾部。当同步状态可用时,AQS 会唤醒队列中的下一个节点所代表的线程。
总结
AQS 是 Java 并发编程中的一个重要组成部分,它提供了构建各种同步工具的基础框架。通过继承 AQS 并实现其提供的模板方法,开发人员可以方便地创建出符合自己需求的同步组件。AQS 的灵活性和可扩展性使其成为 Java 并发工具箱中的重要基石。