目录
1 AQS概述
AQS全称即AbstractQueuedSynchronizer,抽象队列同步器,提供了一套依赖队列实现的FIFO的同步器框架,ReentrantLock,Semaphore,CyclicBarrier,CountDownLatch都是基于AQS实现的
AQS内部维护了一个volatile的state变量和一个CLH队列,框架图如下
2 模板方法模式
AQS定义了一组模版方法供子类覆盖
tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。
tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false。
isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。
2.1 独占方式获取资源
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
首先尝试获取资源,如果获取资源失败则将当前线程以独占的方式添加到执行队列尾部
acquireQueued方法基于CAS不断尝试获取资源,有兴趣的同学可以看看源码实现机制
2.2 独占方式释放资源
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
如果释放资源成功并且队列中有正在等待的线程则通过unparkSuccessor方法唤醒其中一个waitStatus<0的线程
waitStatus有如下几个状态:
// 表征等待线程已取消的
static final int CANCELLED = 1;
// 表征需要唤醒后续线程
static final int SIGNAL = -1;
// 表征线程正在等待触发条件(condition)
static final int CONDITION = -2;
// 表征下一个acquireShared应无条件传播
static final int PROPAGATE = -3;
2.3 共享方式获取资源
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
}
如果获取成功则直接返回。如果获取失败则进入等待队列,自旋的方式不断尝试获取资源
tryAcquireShared方法返回结果说明:
>0:获取资源成功,并且还有剩余资源
=0:获取资源成功,但是已经没有剩余资源
<=:获取资源失败
2.4 共享方式释放资源
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
如果尝试释放资源成功,则进行释放资源并且唤醒下一个线程,返回true,否则返回false
部分内容参考文章:https://www.jianshu.com/p/0f876ead2846