AQS原理浅述

Posted by KANG's BLOG on Tuesday, March 15, 2022

1. 简介

AQS全名:AbstractQueuedSynchronizer,是并发容器J.U.C(java.util.concurrent)下locks包内的一个类。它实现了一个FIFO(FirstIn、FisrtOut先进先出)的队列。底层实现的数据结构是一个双向链表

AQS核心思想是:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态

AQS主要支持两个抽象能力:

  • 共享:多个线程可以同时执行
  • 独占:同一时刻只有一个线程可以执行

2. 概念

State:资源

内部提供了一个声明一个变量state,指代“资源

private volatile int state;

所有操作都是围绕资源的争抢。

Node:节点

每一个抢占资源的线程都被封装成一个Node,每个节点包含前后节点的引用,通过互相关联形成双向链表。

AQS内部包含两个属性head和tail分别指向内部队列的头结点和尾结点。

Node的属性waitStatus,代表等待状态,其自身提供了定义状态的常量:

/** 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;

AQS内部维护了节点(Node)在队列上的进出,继承它的同步器主要需要实现如下方法:

protected boolean tryAcquire(int arg) { } 			// 独占获取

protected boolean tryRelease(int arg) { } 			// 独占释放

protected int tryAcquireShared(int arg) { } 		// 共享获取

protected boolean tryReleaseShared(int arg) { } // 共享释放

protected boolean isHeldExclusively() { } 			// 该线程是否正在独占资源

并未将所有方法声明为abstract而是内部抛出异常,这是为了让使用人员实现共享或者将独占时不必实现另一套机制。

在这些tryXXX方法中主要需要子类控制state的获取行为来完成所需要实现的功能。

比如想实现如下:

需要实现锁的特性,则可以在方法中尝试将state由0改为1,如果此时不为0,表明当前线程未抢占到资源。

state如果允许不断累加,则表示提供了重入性。未获取的state的线程则进入等待队列。