AQS之Semaphore源码分析
1: Semaphore介绍
信号量提供了用于控制资源同时被访问的个数,也就是它会维护一个许可证,访问资源之前需要申请许可证,申请许可证成功后才可以进行访问,如果申请访问资源获取的了许可证,则可以进行资源访问,同时颁发许可证中心的许可证会进行增加,等到访问资源的线程释放资源后,许可证使用情况会进行减少,可用于访问限流等各类限制数量访问等业务。
2: Semaphore加锁逻辑
2.1:acquireSharedInterruptibly(int arg),开始获取资源
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
//判断线程是否中断
if (Thread.interrupted())
throw new InterruptedException();
//判断是否存在空余资源,如果小于零,进行线程中断,添加到队列
if (tryAcquireShared(arg) < 0)
//进行中断
doAcquireSharedInterruptibly(arg);
}
2.2: tryAcquireShared->nonfairTryAcquireShared(int acquires),获取剩余资源数
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
//获取当前可用的资源数
int available = getState();
//默认占用的资源数-可用资源数
int remaining = available - acquires;
if (remaining < 0 ||
//进行cas操作
compareAndSetState(available, remaining))
//返回剩余资源数
return remaining;
}
}
2.3: doAcquireSharedInterruptibly(int arg),进行线程中断
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
//将当前节点添加到队列中
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
//获取上一个节点
final Node p = node.predecessor();
//头节点是否等于上一个节点
if (p == head) {
//获取当前剩余资源数
int r = tryAcquireShared(arg);
//如果存在剩余资源数
if (r >= 0) {
//将当前链表的上一个节点设置为空
setHeadAndPropagate(node, r);
//将上一个节点的下一个节点连接设置为空,进行GC去除
p.next = null; // help GC
failed = false;
return;
}
}
//如果没有剩余资源,进行链表状态修改,并且线程中断
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
2.3.1: addWaiter(Node mode),生成双向链表
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
//获取尾节点
Node pred = tail;
//如果尾节点不为空
if (pred != null) {
//将当前线程的头节点连接到链表尾节点
node.prev = pred;
//cas链表的尾节点添加当前线程,形成双向绑定
if (compareAndSetTail(pred, node)) {
//链表的尾节点添加当前线程,形成双向绑定
pred.next = node;
return node;
}
}
//如果尾节点为空,进行初始化
enq(node);
return node;
}
2.3.1.1:enq(final Node node) 添加尾节点
private Node enq(final Node node) {
//死循环
for (;;) {
//获取尾节点
Node t = tail;
//如果为空
if (t == null) { // Must initialize
//当前节点绑定到尾节点,再次循环
if (compareAndSetHead(new Node()))
tail = head;
} else {
//尾节点赋值给当前节点的头节点
node.prev = t;
//设置尾节点的下一个节点为当前节点
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
2.3.2:doAcquireSharedInterruptibly(int arg),设置上个节点状态
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
//将当前节点添加到队列中
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
//获取上一个节点
final Node p = node.predecessor();
//头节点是否等于上一个节点
if (p == head) {
//获取当前剩余资源数
int r = tryAcquireShared(arg);
//如果存在剩余资源数
if (r >= 0) {
//将当前链表的上一个节点设置为空
setHeadAndPropagate(node, r);
//将上一个节点的下一个节点连接设置为空,进行GC去除
p.next = null; // help GC
failed = false;
return;
}
}
//如果没有剩余资源,进行链表状态修改,并且线程中断
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
3: Semaphore解锁逻辑
3.1:tryReleaseShared(int releases),释放资源
protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
if (compareAndSetState(current, next))
return true;
}
}
3.2:doReleaseShared(),进行资源解锁
private void doReleaseShared() {
for (;;) {
//获取当前节点的头节点
Node h = head;
if (h != null && h != tail) {
//获取上一个节点状态
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
//如果修改失败跳过这次循环
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue; // loop to recheck cases
//成功进行解锁处理
unparkSuccessor(h);
}
//如果状态值不为Node.SIGNAL,修改当前状态Node.PROPAGATE
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}