一、什么是AQS?
全称抽象队列同步器。类如其名,维护了队列同步的一个抽象类,在JCU包中有着基石的作用,比如可重入锁、信号量、CountDownLanch实现它的独享模式或共享模式资源获取或者释放来完成自己的功能,LCH队列图。
二、源码分析
1.先看看关于节点的定义
static final class Node {
/** 共享模式节点 */
static final Node SHARED = new Node();
/** 独占模式节点 */
static final Node EXCLUSIVE = null;
/** 等待状态1 表示取消 */
static final int CANCELLED = 1;
/** -1表示后续节点需要唤醒 */
static final int SIGNAL = -1;
/** 等待condition条件 */
static final int CONDITION = -2;
/**
* 共享模式无条件传播
*/
static final int PROPAGATE = -3;
//等待状态
volatile int waitStatus;
//前面节点
volatile Node prev;
//后续节点
volatile Node next;
}
2.独占模式下的获取
public final void acquire(int arg) {
//tryAcquire交由子类实现 获取到资源返回,获取不到加入到等待队列
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
//前面节点为头结点,且获取成功
if (p == head && tryAcquire(arg)) {
//置为头结点,返回成功
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//失败判断是否应该阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
//没抢到
cancelAcquire(node);
}
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
//前驱节点为-1则本节点可以安心park
if (ws == Node.SIGNAL) //-1
return true;
//剔除>0节点
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//cas设置前驱节点-1,安心park
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
//阻塞 且返回是否中断
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
3.独占模式下的释放
public final boolean release(int arg) {
//重写方法tryRelease成功的时候
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
//唤醒 后面的 返回成功
unparkSuccessor(h);
return true;
}
return false;
}
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
Node s = node.next;
if (s == null || s.waitStatus > 0) {
//置空>0的节点 找到<=0的节点
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
//非空 唤醒
if (s != null)
LockSupport.unpark(s.thread);
}
4.共享模式下的获取
public final void acquireShared(int arg) {
//共享tryAcquireShared<0表示失败 执行doAcquireShared
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
private void doAcquireShared(int arg) {
//设置节点为共享节点 添加到等待队列
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
//前驱节点为head且获取成功 前驱节点设置为head 向后传播结果
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
//非head 当前线程是否应该park
if (shouldParkAfterFailedAcquire(p, node) &&
//&&左边true 右边检查Interrupt且park
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
//前驱节点-1的时候 安心park 等待机会来临
return true;
if (ws > 0) {
//找<=0的节点排在他后边
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//0或者-3 的情况 重试前面节点状态为-1 前驱有机会 他就有机会
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
5.共享模式下的释放
public final boolean releaseShared(int arg) {
//重写方法执行成功 执行 doReleaseShared
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
//cas+循环重试修改状态到0
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
//尝试找到非cancel后续节点 unpark
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
// 就一个节点了 或者为null 跳出循环
if (h == head)
break;
}
}
三、手写一个AQS (这里参考某易老师的代码)
//抽象队列同步器
//state owner waiters
public class MasterAqs {
//acquire acquireShared :定义了资源争用的逻辑,如果没拿到 则等待;
//tryAcquire tryAcquireShared: 实际执行占资源的操作 如何判定由使用者具体去实现
//release releaseShared 定义释放资源的逻辑 释放之后通知后续节点进行争抢
//tryRelease tryReleaseShared 实际执行资源释放的操作 具体的Aqs由使用者去实现;
//1. 如何判断一个锁的状态或者说拥有者
AtomicReference<Thread> owner = new AtomicReference<>();
//保存 正在等待的线程
volatile LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>();
//资源状态
volatile AtomicInteger state = new AtomicInteger(0);
//交给使用者去实现 模板方法的体现
public boolean tryAcquire(){
throw new UnsupportedOperationException();
}
//共享资源占用逻辑 返回资源占用情况
public int tryAcquireShared (){
throw new UnsupportedOperationException();
}
public void acquireShared(){
while(tryAcquireShared()<0){
boolean addQ = true;
if(addQ){
//没拿到锁 ,加入到等待队列
waiters.offer(Thread.currentThread());
addQ=false;
}else{
//阻塞 挂起当前线程不要往下跑
LockSupport.park(); //伪唤醒 就是非unpark唤醒的
}
}
}
public void acquire(){
boolean addQ = true;
while (!tryAcquire()) {
if(addQ){
//没拿到锁 ,加入到等待队列
waiters.offer(Thread.currentThread());
addQ=false;
}else{
//阻塞 挂起当前线程不要往下跑
LockSupport.park(); //伪唤醒 就是非unpark唤醒的
}
}
waiters.remove(Thread.currentThread());
}
public void release(){
if(tryRelease()){
//释放Lock
//通知等待者
Iterator<Thread> iterator=waiters.iterator();
while(iterator.hasNext()){
Thread next=iterator.next();
LockSupport.unpark(next);
}
}
}
//交给使用者去实现 模板方法的体现
public boolean tryRelease(){
throw new UnsupportedOperationException();
}
public boolean tryReleaseShared(){
throw new UnsupportedOperationException();
}
public void releaseShared(){
if(tryReleaseShared()){
//释放Lock
//通知等待者
Iterator<Thread> iterator=waiters.iterator();
while(iterator.hasNext()){
Thread next=iterator.next();
LockSupport.unpark(next);
}
}
}
public AtomicInteger getState() {
return state;
}
public void setState(AtomicInteger state) {
this.state = state;
}
}
独占资源AQS实现类的例子
public class MasterLockByAqs implements Lock {
MasterAqs aqs=new MasterAqs(){
@Override
public boolean tryAcquire() {
return owner.compareAndSet(null, Thread.currentThread());
}
@Override
public boolean tryRelease() {
return owner.compareAndSet( Thread.currentThread(),null);
}
};
@Override
public boolean tryLock() {
return aqs.tryAcquire();
}
@Override
public void lock() {
aqs.acquire();
}
//T2 unlock之后通知T1线程
@Override
public void unlock() {
aqs.release();
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public Condition newCondition() {
return null;
}
}
四、总结
其实我们只需要懂共享资源和独占资源的实际含义,再演绎推理就能提会到Doug Lea设计cas的巧妙之处。维护一个节点(队列)链表,然后使用cas这种原子操作模式,外加循环,实际源码还考虑了interupt操作。