AQS,全称是 AbstractQueuedSynchronizer,是 Java 中用于构建锁和同步器的框架。它提供了一种基于 FIFO 等待队列的、可重入的、灵活的同步框架,用于构建各种同步工具类,例如 ReentrantLock、Semaphore、CountDownLatch 等。AQS 的设计目标是提供一种通用的机制,使得开发者能够相对容易地构建出高效且正确的同步工具。
AQS 的主要思想是使用一个状态变量来表示资源的状态,通过 CAS 操作来进行状态的原子性修改,通过 FIFO 等待队列来管理阻塞线程。AQS 的设计采用了模板方法设计模式,定义了一些抽象的方法,子类可以通过实现这些方法来定义自己的同步器。以下是 AQS 的一些关键方法:
acquire(int arg):
- 该方法尝试获取共享资源,如果获取失败则会进入等待队列并阻塞。
- 具体的实现由子类提供,通常是通过 CAS 操作来修改状态。
release(int arg):
- 该方法释放共享资源,通常在释放资源后,会唤醒等待队列中的一个线程。
- 具体的实现也由子类提供。
tryAcquire(int arg)和tryRelease(int arg):
- 与
acquire和release类似,但是它们是非阻塞的尝试版本,用于实现非阻塞的获取和释放。
hasQueuedPredecessors():
- 判断当前线程是否在等待队列中有前驱节点,用于实现公平性策略。
isHeldExclusively():
- 判断当前线程是否持有独占资源。
AQS 的核心思想是通过维护一个状态变量和等待队列来实现同步。状态变量可以表示资源的数量,也可以表示锁的状态等。等待队列用于存储等待获取共享资源或独占资源的线程。
AQS的设计思想主要包括以下几个核心概念:
1. 状态变量:
AQS维护一个状态变量,它可以表示资源的数量,也可以表示锁的状态等。状态的变化由子类具体实现,通过原子性的操作(通常是CAS操作)来修改状态。
2. FIFO等待队列:
AQS使用一个FIFO(先进先出)的等待队列来管理等待获取共享资源或独占资源的线程。当一个线程需要获取资源但当前资源已被其他线程占用时,该线程会被放入等待队列中。当资源释放后,等待队列中的线程按照先进先出的顺序被唤醒。
3. 模板方法设计模式:
AQS采用模板方法设计模式,定义了一些抽象的方法,由子类实现以定义自己的同步器。这些方法包括acquire、release、tryAcquire、tryRelease等,它们为同步器的使用者提供了可定制的扩展点。
4. 公平性策略:
AQS提供了hasQueuedPredecessors方法用于判断当前线程是否在等待队列中有前驱节点,从而实现公平性策略。公平性策略指的是等待时间较长的线程优先获得资源,以避免线程饥饿的问题。
5. Condition接口:
AQS通过Condition接口实现了条件变量,允许线程在某个条件上等待,并在条件发生变化时被唤醒。Condition接口提供了await、signal、signalAll等方法,用于实现更复杂的线程协作。
AQS 的设计使得同步器的实现变得相对简单,只需要关注自己业务逻辑的同步规则,而不用考虑线程的排队、唤醒等底层细节。通过继承 AQS,开发者可以构建出各种灵活强大的同步工具类,从而更好地满足多线程编程中的需求。