一、AQS分析
1.原理概述
AQS全称`AbstractQueuedSynchronizer`,java中几乎所有锁均是基于AQS做的实现,AQS原理是基于CLH算法的
双向队列,AQS提供队列的基础操作和锁判定,子类提供上层封装,实现诸如公平/非公平锁、try之类操作、基于互斥共享锁实现读写锁等
2.重要属性
- Node节点
static final class Node {
/** 标记当前是共享节点 */
static final Node SHARED = new Node();
/** 标记当前节点是独享节点 */
static final Node EXCLUSIVE = null;
/** 节点状态:已取消,在唤醒流程中,因为是从队尾开始查找,已取消的节点会被过滤 */
static final int CANCELLED = 1;
/** 节点状态:待唤醒,等待前一个节点释放锁后,唤醒当前节点对应的线程 */
static final int SIGNAL = -1;
/** 节点状态:当前节点在条件队列,当条件队列的节点被singal后,会由CONDITION变为出事状态0,再转为SIGNAL状态并进入到同步队列 */
static final int CONDITION = -2;
/** 节点状态:传播状态,用在读写锁场景,只能用于头结点,表示头结点的状态能够传递下去 */
static final int PROPAGATE = -3;
/**
* 节点状态
*/
volatile int waitStatus;
/**
* 同步队列——前节点
*/
volatile Node prev;
/**
* 同步队列——后节点
*/
volatile Node next;
/**
* 当前节点对应的线程
*/
volatile Thread thread;
/**
* 当前节点在条件队列下一个等待节点
*/
Node nextWaiter;
}
- Head/Tail
条件队列的头尾节点,Head节点是已经获取到锁的节点,Tail节点为队尾节点,每次查询应当唤醒节点的时候,都是从队尾节点开始扫描 - state
AQS的同步队列状态,默认为0,是否锁定通过其来判定,加锁过程是对其累加,解锁是对其进行减去加锁累加的值,在重入锁过程中 - xxOffset(stateOffset/headOffset...)
记录相关属性的地址偏移量,并通过CAS操作对其进行修改
3.同步队列之acquire流程
4.同步队列之release流程
5.条件队列之await流程
6.条件队列之signal流程
7.同步队列与条件队列
二、总结
1.AQS的同步队列为等待获取锁的队列,Head节点为已经获得到锁的节点,head节点release后,通过unpark唤醒后续等待节点,head节点继续for循环,通过tryAcqure加锁成功后,将自己设置为同步队列的新的头结点
2.AQS通过state和exclusiveOwnerThread来实现加解锁和可重入锁