Java Semaphore 原理与实战解析
Java Semaphore 原理与实战解析
参考文献:
[2] 官方文档:Java Semaphore API
[3] 源码参考:JDK Semaphore 源码
一、概述与名词解释
1.1 技术背景
在多线程并发编程中,资源访问冲突是常见问题。Java 并发包(java.util.concurrent)提供了多种同步工具,其中 Semaphore(信号量) 是一种经典的限流与资源计数器方案。早在 1965 年 Edsger Dijkstra 就提出了信号量机制,用于操作系统进程协作,随后成为操作系统和分布式系统中的基础同步原语。
1.2 相关术语
- Semaphore(信号量):一种用于控制同时访问特定资源线程数量的同步工具。
- Permit(许可):信号量内部的计数,每个线程获取/释放资源时会增减许可数量。
- AQS(AbstractQueuedSynchronizer):JDK 并发包的核心同步队列实现,Semaphore 基于 AQS 实现。
- 公平/非公平锁:公平锁保证按照请求顺序分配许可,非公平锁可能插队。
1.3 应用场景
- 连接池限流
- 限制接口并发
- 控制资源访问(如数据库、文件等)
二、主流程分解
Semaphore 的核心流程包括 初始化、获取许可(acquire)、释放许可(release) 三大环节。
2.1 初始化
设计思想:通过构造器设置最大许可数,底层将许可数赋值到 AQS 的 state 字段。
技巧与优缺点:
- 优点:灵活控制并发度,支持公平/非公平模式。
- 缺点:许可数一旦设置,动态调整需重建对象。
业务场景举例:
如限制同时最多2个线程访问某个资源:
Semaphore semaphore = new Semaphore(2);
2.2 获取许可
设计思想:线程尝试原子性获取许可,许可不足则挂起线程并加入同步队列。
流程简述:
- 检查 state 是否足够,state >= 1 则减1并返回。
- state < 1 时,构造 Node 节点加入阻塞队列,挂起线程。
- 唤醒后重试,直到获取成功。
优缺点:
- 优点:避免资源争抢,线程安全。
- 缺点:可能发生线程饥饿(非公平模式)。
业务场景举例:
API限流,每秒只允许2个请求并发处理。
2.3 释放许可
设计思想:释放许可时增加 state,并唤醒阻塞队列中等待的线程。
流程简述:
- state 加1。
- 唤醒阻塞队列所有共享节点。
优缺点:
- 优点:高效唤醒,保证并发性。
- 缺点:唤醒所有节点可能导致“惊群效应”。
业务场景举例:
数据库连接归还后,唤醒等待连接的线程。
三、流程图与源码解析
3.1 流程图(flowchart)
3.2 状态图(stateDiagram-v2)
3.3 时序图(sequenceDiagram)
3.4 核心源码与速记口诀
关键源码目录
public class Semaphore {
private final Sync sync; // AQS同步器
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public void release() {
sync.releaseShared(1);
}
}
acquire源码注释
public void acquire() throws InterruptedException {
// 1. 尝试原子性获取许可
sync.acquireSharedInterruptibly(1);
}
口诀:
初始化定许可,获取原子减,失败入队挂,释放加一唤。
四、调试与优化技巧
4.1 调试技巧
- 利用 JDK VisualVM 或 JMC 监控阻塞队列长度、线程状态。
- 打印 AQS state 变化,定位许可分配异常。
- 仔细检查 acquire/release 对应关系,防止“死锁”或“泄漏”。
4.2 性能优化
- 使用非公平模式提升吞吐量(但可能导致部分线程饥饿)。
- 合理设置许可数,避免过度唤醒。
- 与 ThreadPoolExecutor 结合,限流任务提交。
4.3 技术栈集成
- 与 Redis、ZooKeeper 实现分布式信号量(Redisson Semaphore)。
- Spring Boot 提供 @Async + Semaphore 控制接口并发。
4.4 高阶应用
- 自定义 Semaphore 子类,实现动态许可调整。
- 支持限流降级、熔断等扩展。
五、底层实现与架构演进
5.1 底层机制
- 核心依赖 AQS 的 state 字段和同步队列(CLH队列)。
- 许可获取/释放均为 CAS 原子操作,保证线程安全。
- 节点唤醒采用 LockSupport.park/unpark 实现线程挂起/唤醒。
5.2 架构演进
- JDK 早期采用 synchronized + wait/notify 实现,性能较差。
- JDK5+ 引入 AQS,统一同步机制,提升并发性能。
- 现代分布式系统采用 Redis/ZK 等实现跨进程信号量。
六、全文总结
Semaphore 是 Java 并发编程中的重要同步工具,适用于限流、资源池等场景。其底层基于 AQS,同步队列和原子操作保证线程安全。理解信号量的原理、流程和源码,有助于开发高效可靠的并发系统。调试和优化 Semaphore 需关注许可数设置、阻塞队列管理及与其他技术栈的集成。随着架构演进,信号量已扩展至分布式系统领域,成为现代限流方案的重要基础。
知其然,更知其所以然,Semaphore是并发限流的基石。
欢迎交流讨论,更多并发编程内容敬请关注!
更多推荐



所有评论(0)