Semaphore 限流器源码解析 AQS 共享模式实现原理详解
各位Java开发者,在上一篇深入解析AQS独占模式与ReentrantLock之后,我们已经掌握了处理“互斥访问”的核心技术。然而,在实际的高并发系统设计与性能优化中,仅仅实现互斥是远远不够的。我们经常需要更精细的并发控制能力——精确管理同一时刻能够访问特定资源的线程数量。无论是实现API限流、数据库连接池管理、还是控制并行任务执行数量,这些场景都需要一种更强大的并发控制机制。
免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
这一切功能背后的技术基石,正是AQS的共享模式。它是Semaphore(信号量)、CountDownLatch(倒计时器)、CyclicBarrier(循环屏障)等Java并发工具类的通用底层架构。理解AQS共享模式的工作原理,是掌握Java高并发编程的关键一步。

一、核心区别:AQS独占模式与共享模式对比
要快速理解两者的本质差异,只需记住这一句话:
- 独占模式(Exclusive Mode):资源具有排他性,同一时刻仅允许一个线程持有。典型实现是ReentrantLock可重入锁。
- 共享模式(Shared Mode):资源具有可共享性,允许多个线程同时持有。Semaphore信号量、CountDownLatch等工具都基于此模式构建。
二、AQS共享模式核心架构(基于JDK8源码)
首先查看AQS中支持共享模式的关键字段定义:
public abstract class AbstractQueuedSynchronizer {
// 共享状态:多个线程可以同时访问和修改
private volatile int state;
// CLH同步队列头尾指针
private transient volatile Node head;
private transient volatile Node tail;
}
共享模式的设计思想非常直观易懂:
state字段在此模式下代表“可用资源的总数量”。- 线程申请资源时,通过CAS操作将
state值减1;释放资源时,将state值加1。 - 只要
state > 0,就表示还有可用资源,允许多个线程并发获取。
三、AQS共享模式核心源码深度解析
1. 核心入口方法:acquireShared(int arg)
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0) {
// 获取资源失败 → 进入同步队列等待
doAcquireShared(arg);
}
}
这个方法有几个关键设计要点:
tryAcquireShared是模板方法,由具体的子类(如Semaphore、CountDownLatch)实现其具体逻辑。- 返回值语义:返回值≥0表示获取资源成功;返回值<0则表示获取失败,当前线程需要进入同步队列等待。
2. 核心逻辑:doAcquireShared入队与阻塞机制
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);
if (r >= 0) {
// 获取成功 → 传播唤醒后续的共享节点
setHeadAndPropagate(node, r);
p.next = null;
if (interrupted)
selfInterrupt();
failed = false;
return;
}
}
// 检查并执行线程阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
共享模式最显著的特征就体现在这里:唤醒传播机制(propagation)。当一个共享节点被唤醒并成功获取资源后,它会通过setHeadAndPropagate方法,主动尝试唤醒同步队列中后续的所有共享节点。这种设计实现了“连锁唤醒”效果,让多个等待线程能够高效地批量恢复执行,极大提升了并发性能。
3. 资源释放:releaseShared方法
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
// 释放成功 → 唤醒队列中的等待节点
doReleaseShared();
return true;
}
return false;
}
这里的doReleaseShared方法是AQS共享模式唤醒机制的核心。它通过循环检查和传播唤醒的算法,确保所有在同步队列中等待的共享线程都能被正确、高效地唤醒,避免了“唤醒丢失”问题。
四、Semaphore源码深度剖析(限流核心工具)
Semaphore是AQS共享模式最经典的应用实现,它的核心功能是控制最多N个线程同时访问特定资源。
1. Semaphore内部结构(JDK8实现)
public class Semaphore {
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
Sync(int permits) {
setState(permits); // permits = 初始许可证数量
}
}
// 非公平同步器(默认实现)
static final class NonfairSync extends Sync {
protected int tryAcquireShared(int acquires) {
return nonfairTryAcquireShared(acquires);
}
}
// 公平同步器
static final class FairSync extends Sync {
protected int tryAcquireShared(int acquires) {
// 先检查同步队列,再尝试获取
}
}
}
2. 核心逻辑:非公平模式获取许可证
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int a vailable = getState();
int remaining = a vailable - acquires;
if (remaining < 0 ||
compareAndSetState(a vailable, remaining))
return remaining;
}
}
这段代码的逻辑清晰明了:
- 获取当前可用许可证数量(从
state字段读取)。 - 计算获取指定数量后的剩余许可证(
remaining = state - acquires)。 - 如果
remaining ≥ 0且CAS设置状态成功,则获取成功。 - 如果
remaining < 0,则获取失败,线程将进入AQS同步队列等待。
3. 许可证释放实现
protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
int next = current + releases;
if (compareAndSetState(current, next))
return true;
}
}
释放操作本质上是增加state值(可用许可证数量),然后通过AQS的doReleaseShared方法唤醒同步队列中等待的线程,让它们有机会获取新释放的资源。
五、公平信号量与非公平信号量对比
这是使用Semaphore时需要理解的重要选择:
- 非公平模式(默认):线程获取许可证时,会先直接尝试CAS抢占,抢不到再进入队列等待。这种方式减少了线程切换开销,吞吐量更高。
- 公平模式:线程获取许可证前,会先检查AQS同步队列中是否有其他线程在等待。如果有,则自己必须入队等待,严格遵循先来后到的顺序,避免了线程“饥饿”问题。
对于大多数业务场景,使用默认的非公平模式即可获得最佳性能。只有在需要严格保证公平性的特殊场景下,才需要考虑使用公平模式。
六、Semaphore实战应用场景(可直接落地)
理解了Semaphore的实现原理,我们来看看它在实际系统中的典型应用:
- API接口限流:限制某个关键接口同时处理的请求数不超过预设阈值(如20个)。
- 数据库连接池控制:管理访问数据库连接等稀缺资源的并发数量。
- 多线程任务流速控制:防止瞬间提交大量任务导致线程池过载,实现平滑的任务处理。
- 系统资源访问控制:控制同时访问文件、网络连接等系统资源的线程数量。
标准的使用模板如下,务必注意在finally块中释放许可证,避免资源泄漏:
Semaphore semaphore = new Semaphore(20);
try {
semaphore.acquire(); // 获取许可证
// 执行受保护的业务逻辑
} finally {
semaphore.release(); // 必须释放许可证
}
七、Java并发体系完整串联
至此,我们可以将JUC并发工具包的核心脉络完整串联起来:
- ReentrantLock → 基于AQS独占模式,解决资源互斥访问问题。
- Semaphore → 基于AQS共享模式,解决资源数量控制与限流问题。
- CountDownLatch → 同样是AQS共享模式的应用(state减到0时唤醒所有等待线程)。
- CyclicBarrier → 基于ReentrantLock和Condition实现,解决线程同步等待问题。
- ThreadPoolExecutor → 其内部的工作线程控制、状态管理也大量运用了AQS的设计思想。
掌握了AQS的独占与共享这两种核心模式,意味着你已经打通了Java并发编程最底层的技术逻辑。这不仅能够帮助你深入理解JUC中各种并发工具的实现原理,更能让你在实际开发中设计出更高效、更稳定的并发控制系统。
热门专题
热门推荐
这项由清华大学、美团、香港大学等多家顶尖机构联合开展的研究,于2026年3月以预印本论文(arXiv:2603 25823v1)的形式发布。它直指当前AI视觉生成领域一个被长期忽视的核心问题:这些能画出“神作”的模型,到底有多“聪明”?研究团队为此构建了一套全新的测试基准——ViGoR-Bench,
人工智能的浪潮席卷了各个领域,机器在诸多任务上已展现出超越人类的能力。然而,有一个看似寻常却异常复杂的领域,始终是AI研究者们渴望攻克的堡垒——让机器像真正的学者那样,撰写出一篇结构严谨、逻辑自洽、图文并茂的完整科学论文。这远比下棋或识图要困难得多。 2026年3月,一项由中科院AgentAlpha
这项由法国Hornetsecurity公司与里尔大学、法国国家信息与自动化研究院(Inria)、法国国家科学研究中心(CNRS)以及里尔中央理工学院联合开展的研究,发表于2026年3月31日的计算机科学期刊,论文编号为arXiv:2603 29497v1。 在信息爆炸的今天,我们每天都在网上留下数字
当你满怀期待地拆开一台全新的智能设备,最令人困扰的往往不是如何使用它,而是如何让它真正“理解”指令并智能地执行任务。如今,一个更为优雅的解决方案可能已经出现。来自清华大学深圳国际研究生院与哈尔滨工业大学(深圳)的联合研究团队,近期取得了一项极具前瞻性的突破:他们成功训练人工智能自主“撰写”并精准理解
2026年3月,来自华盛顿大学、艾伦人工智能研究所和北卡罗来纳大学教堂山分校的研究团队,在图像智能矢量化领域取得了一项突破性进展。这项研究(论文编号:arXiv:2603 24575v1)开发了一个名为VFig的AI系统,它能够将静态的栅格图像智能地转换为可自由编辑的矢量图形,如同一位“图形考古学家





