Semaphore.release()方法的底层原理
一、release() 方法代码解析
当调用 release() 方法时,实际调用的是 AQS 的 releaseShared(1) 方法。以下是其详细工作流程:
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
1、Semaphore.release()
public void release() {
sync.releaseShared(1); // 调用 AQS 的共享模式方法
}
2、AQS.releaseShared(int arg)
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) { // 尝试释放许可
doReleaseShared(); // 唤醒等待线程
return true;
}
return false;
}
3、Semaphore.tryReleaseShared(int releases)
protected boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState(); // 当前剩余许可数
int next = current + releases; // 计算新的许可数
if (next < current) {
throw new Error("Maximum permit count exceeded"); // 防止溢出
}
if (compareAndSetState(current, next)) { // CAS 更新 state
return true; // 成功释放许可
}
}
}
4、AQS.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; // CAS 失败,重试
}
unparkSuccessor(h); // 唤醒后继节点
} else if (ws == 0 && !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) {
continue; // CAS 失败,重试
}
}
if (h == head) { // 头节点未变化,退出循环
break;
}
}
}
二、release() 的工作流程
当调用 release() 方法时,实际调用的是 AQS 的 releaseShared(1) 方法。以下是其详细工作流程:
(1)、增加许可数
1、调用 tryReleaseShared(arg):
-
tryReleaseShared(arg) 是 AQS 的模板方法,由 Semaphore 实现。
-
在 Semaphore 中,tryReleaseShared(arg) 的逻辑是通过 int next = current + releases; 操作将 state 增加 1。
2、CAS 操作:
-
使用 compareAndSetState(current, next) 方法原子性地更新 state 变量。
-
如果 CAS 成功,表示线程成功释放许可;否则,重试。
(2)、唤醒等待线程
1、检查等待队列:
-
如果 CLH 队列中有等待的线程,AQS 会唤醒队列中的第一个有效节点(线程)。
-
被唤醒的线程会重新尝试获取许可。
2、传播唤醒:
- 在共享模式下,AQS 会传播唤醒信号,确保所有等待的线程都有机会获取许可。

浙公网安备 33010602011771号