一、简介
Java同步器AbstractQueuedSynchronizer简称AQS,JDK中很多并发工具类的内部实现都依赖于AQS,如ReentantLock、Semaphore、CounDownLatch、ThreadPoolExecutor等。AQS的设计基于模板方法模式,实际开发中需要继承AQS并重写指定的方法,将其组合在并发组件的实现中,而AQS在模板方法中封装了同步状态管理、线程排队、等待与唤醒等底层操作。
二、AQS基本构成
- 2.1 数据结构
AQS依赖内部的同步队列(FIFO的双向链表)来完成同步状态的管理,AQS内容主要有三个重要的成员变量,分别是头节点(head)、尾节点(tail)和资源状态(state),如下。其中state表示一种共享的资源状态,在不同的实现中有不同的含义,如ReentrantLock锁中它表示锁是否被占用;在semaphore中,它表示剩余的数量;在CountDownLatch中,它表示需要全部完成的数量。
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable {
...
private transient volatile Node head;
private transient volatile Node tail;
private volatile int state;
...
}
AQS中维护的双向链表核心依赖于节点(Node),节点的定义如下,其中prev、next表示该节点的前置、后置节点,构成AQS的双向链表;waitStatus表示节点线程的状态;thread表示节点包含的线程。如果当前线程获取同步状态失败,则同步器会将当前线程以及等待状态的信息封装成一个节点加入到同步队列中,阻塞当前线程,当同步器状态释放是,会把队列中的首节点中的线程唤醒,并使其尝试获取同步状态。
static final class Node {
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
Node nextWaiter;
...
}
节点线程的状态(waitStatus)的分类为:
节点状态名 | 节点状态描述 |
---|---|
CANCELLED(1) | 取消状态。这是一个终结状态 |
SIGNAL(-1) | 等待触发状态。该节点的后继节点线程处于等待状态,当前线程释放同步状态或取消,会唤醒后继节点线程 |
CONDITION(-2) | 等待条件状态。该节点在等待队列中,其它线程对Condition调用signal后,该节点从等待队列转移到同步队列 |
PROPAGATE(-3) | 向后传播状态 |
0 | 初始状态 |
- 2.2 主要方法
继承AQS时可重写的方法,重写的尝试获取/释放锁的过程应当是无阻塞的:
方法名称 | 方法描述 |
---|---|
boolean tryAcquire(int arg) | 尝试获取独占锁 |
boolean tryRelease(int arg) | 尝试释放独占锁 |
int tryAcquireShared(int arg) | 尝试获取共享锁 |
boolean tryReleaseShared(int arg) | 尝试释放共享锁 |
boolean isHeldExclusively() | 判断当前线程是否获取了独占锁 |
AQS提供的主要模板方法:
方法名称 | 方法描述 |
---|---|
void acquire(int arg) | 获取独占锁。会调用用户实现的tryAcquire方法,如果获取失败,则将当前线程封装成节点进入同步队列等待 |
void acquireInterruptibly(int arg) | 如果当前线程被中断,则抛出中断异常。其它同acquire |
boolean tryAcquireNanos(int arg, long nanosTimeout) | 如果当前线程在超时时间内获取到同步状态,则返回true,否则返回false。其它同acquireInterruptibly |
boolean release(int arg) | 释放独占锁。会调用用户实现的tryRelease方法,释放后将同步队列的第一个节点的线程唤醒 |
void acquireShared(int arg) | 获取共享锁。会调用用户实现的tryAcquireShared方法,如果获取失败,将当前线程封装成节点进入同步队列等待,可同时有多个线程获取锁 |
void acquireShared(int arg) | 获取共享锁。会调用用户实现的tryAcquireShared方法,如果获取失败,将当前线程封装成节点进入同步队列等待,可同时有多个线程获取锁 |
void acquireSharedInterruptibly(int arg) | 如果当前线程被中断,则抛出中断异常。其它同acquireShared |
boolean tryAcquireSharedNanos(int arg, long nanosTimeout) | 如果当前线程在超时时间内获取到同步状态,则返回true,否则返回false。其它同acquireSharedInterruptibly |
boolean releaseShared(int arg) | 释放共享锁。会调用用户实心的tryReleaseShared方法 |
三、独占式获取或释放
见下一篇
四、共享式获取或释放
见下下一篇