AbstractQueuedSynchronizer(AQS)

1 定义

提供一种原子式管理同步状态、阻塞和唤醒线程功能,以及队列模型的简单框架。

Java中大部分同步类(Lock、Semaphoer、ReentrantLock等)都是基于AQS实现的。

以下定义来自JDK 14:

提供了一个实现阻塞锁和相关同步器的框架,其依赖于FIFO等待队列。

使用整型数值表示状态,不同实现各自定义数值对于获取和释放的语义。

子类通过定义为非公有内部类实现同步。子类调用AQS方法实现同步。

AQS提供了两种实现模式,可以只实现一种或同时实现(如ReadWriteLock)。排他模式同一时刻只允许一个线程获取成功;而共享模式允许多个线程获取成功。不同的模式使用同一个等待队列。

提供一个嵌套的、可供实现排他模式的子类使用的Condition实现,ConditionObject。isHeldExclusively报告是否与当前线程排他,release完全释放,acquire保存当前状态并最终恢复。需要保证没有其他的AQS方法创建类似条件。

AQS提供了检查、操作和监控内部队列和条件对象的方法。

序列化值保存状态值,不会保存等待队列。通常需要序列化的实现需要定义一个readObject方法用于恢复。

唯一实现AQS需要实现方法,方法内部应当线程安全且无阻塞:

  • tryAcquire
  • tryRelease
  • tryAcquireShared
  • tryReleaseShared
  • isHeldExclusively

实现检查和更改状态,需要实现:

  • getState
  • setState
  • compareAndSetState

AbstractOwnableSynchronizer提供了拥有排他同步器的线程,可用于监测和诊断持有锁的线程。

虽然内部基于FIFO队列,但是并没有强制使用FIFO。

1
2
3
4
5
6
7
8
9
Acquire:
while (!tryAcquire(arg)) {
enqueue thread if it is not already queued;
possibly block current thread;
}

Release:
if (tryRelease(arg))
unblock the first queued thread;

Barging: 因为尝试获取在入队之前,因此存在多个线程通过检查并且后者先于前者入队的情形。可以在内部再调用多个检查防止此类情形,以确保顺序。

AQS

2 原理

使用volatile修饰的整型变量表示同步状态,利用CLH实现的FIFO队列对线程排队,使用CAS完成对同步状态的修改。

CLH:一种单向链表。AQS使用CLH变体的虚拟双向队列。

3 重入锁

一个线程可对持有资源重复加锁。

ReentrantLock&Synchronized

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// **************************Synchronized的使用方式**************************
// 1.用于代码块
synchronized (this) {}
// 2.用于对象
synchronized (object) {}
// 3.用于方法
public synchronized void test () {}
// 4.可重入
for (int i = 0; i < 100; i++) {
synchronized (this) {}
}
// **************************ReentrantLock的使用方式**************************
public void test () throw Exception {
// 1.初始化选择公平锁、非公平锁
ReentrantLock lock = new ReentrantLock(true);
// 2.可用于代码块
lock.lock();
try {
try {
// 3.支持多种加锁方式,比较灵活; 具有可重入特性
if(lock.tryLock(100, TimeUnit.MILLISECONDS)){ }
} finally {
// 4.手动释放锁
lock.unlock()
}
} finally {
lock.unlock();
}
}

参考资料

java.util.concurrent.locks.AbstractQueuedSynchronizer

JavaGuide/docs/java/Multithread/AQS.md

从ReentrantLock的实现看AQS的原理及应用