一、AQS
1.1 概述
全称为(AbstractQueuedSynchronizer, AQS) ,队列同步器
- 用来
构建锁或其他同步组件
的基础框架,使用了一个java volatile int state
成员变量表示同步状态
(代表共享资源),通过内置的FIFO双向队列
来完成资源获取线程的排队工作; - 定义为volatile能够保证
多线程下的可见性
,当state = 1时代表当前对象锁已经被占有,其他线程加锁会失败。加锁失败的线程会被放入一个FIFO队列中.
1.2 主要使用方式
因采用模板方法模式继承,子类通过继承同步器并实现它的抽象方法来管理同步器
1.3 主要方法
1. getState():获取当前同步状态
2. setState(int newState):设置当前同步状态
3. compareAndSetState(int expect、update):使用CAS来设置当前状态,保证状态设置的原子性;
4. 独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源
状态的改变主要通过这三个方法来进行,而且state的操作都是通过CAS来保证其并发修改的安全性。
二、底层原理
底层是一个FIFO双向队列
,队列上是一个个节点Node,Node是内部类,封装了一些信息,主要有:
static final class Node {
/*
* 1. signal = -1, 后继节点的线程处于等待状态。如果当前线程释放了同步状态,
* 将会通知后继节点,使后继节点的线程得以运行
* 2. condition = -2, 节点在【等待队列】中,节点线程等待在Condition上,当其它
* 线程对Condition调用了signal()方法后,该节点将会从等待队列中转移到同步队列,
* 加入对同步状态的获取中
*/
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread; // 获取同步状态的线程
Node nextWaiter; // 等待队列中的后继节点
}
2.1 独占式同步状态获取和释放
获取逻辑: 主要是java acquire
来完成,该方法定义了一个抽象模板,内部的java tryAcquire
方法由子类来实现,java acquireQueued(addWaiter)
是默认实现方法。
释放逻辑: 主要由java release
方法来实现,该方法也是模板模式,````java tryRelease方式需要由子类自己实现,
java unparkSuccessor```唤醒方法由默认实现。具体流程如下:
2.2 共享式同步状态获取和释放
与独占式的区别在于,同一时刻一个资源能否被多个线程访问
。AQS也提供了共享式同步状态获取和释放的模板模式方法,分别为acquireShared和releaseShared。
加锁流程: 和独占式类似,不过提供的由子类实现的tryAcquireShared方法,返回值为int,当返回值 >= 0的时候,可以认为获取锁成功,否则,进入同步队列;
解锁流程: 和独占式类似,需要子类实现tryReleaseShared方法,来保证锁的释放。