前言:为什么要了解AQS?
在如今有很多高并发的场景下,都免不了使用多线程,使用多线程就避免不了了解锁。之前也提到了synchronized锁(参见文章synchronized锁),另一个常用的锁就是ReentrantLock,而ReentrantLock底层实现就是AQS,当然还有很多其他的实现,接下来我们一起了解下。
一、AQS是什么?
AQS全称:AbstractQueuedSynchronizer,抽象队列式同步器。
AQS是一个抽象类,它定义了一套多线程访问共享资源的同步器框架。通俗解释,AQS就像是一个队列管理员,当多线程操作时,对这些线程进行排队管理。
AQS本身是一个抽象类,所以并没有单独实现什么功能,但是很多功能都继承了AQS类,依赖于其底层支持。如:ReentrantLock、Semaphore、CountDownLatch、CycleBarrier。
二、AQS如何实现的?
AQS主要通过维护了两个变量来实现同步机制的
2.1、state
AQS使用一个volatile修饰的私有变量来表示同步状态,当state=0表示释放了锁,当state>0表示获得锁。
/**
* The synchronization state.
*/
private volatile int state;
另外,AQS提供了以下三个方法来对state进行操作。
protected final int getState() {
return state;
}
protected final void setState(int newState) {
state = newState;
}
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
2.2、FIFO同步队列
AQS通过内置的FIFO同步队列,来实现线程的排队工作。
如果线程获取当前同步状态失败,AQS会将当前线程的信息封装成一个Node节点,加入同步队列中,并且阻塞该线程,当同步状态释放,则会将队列中的线程唤醒,重新尝试获取同步状态。
static final class Node {
/** Marker to indicate a node is waiting in shared mode */
static final Node SHARED = new Node();
/** Marker to indicate a node is waiting in exclusive mode */
static final Node EXCLUSIVE = null;
/** waitStatus value to indicate thread has cancelled */
static final int CANCELLED = 1;
/** waitStatus value to indicate successor's thread needs unparking */
static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
static final int PROPAGATE = -3;
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
Node nextWaiter;
/**
* Returns true if node is waiting in shared mode.
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
* Returns previous node, or throws NullPointerException if null.
* Use when predecessor cannot be null. The null check could
* be elided, but is present to help the VM.
*
* @return the predecessor of this node
*/
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException()<