Java 并发神器 Semaphore 深度剖析与源码整理
·
Java 并发神器 Semaphore 深度剖析与源码整理
关键词:并发控制、限流、AQS、Semaphore、源码注释、流程图、业务场景
一、概述
在高并发、多线程开发场景下,资源限流与线程同步是系统稳定性和性能保障的核心。Java 并发包 java.util.concurrent 中的 Semaphore(信号量)类,就是解决这一问题的明星工具。它通过“许可”机制,优雅地控制同时访问共享资源的线程数量,广泛应用于数据库连接池、接口限流、分布式任务等场景。
本文将围绕 Semaphore 项目源码,展开全面校正与整理,结合结构化注释、主接口梳理、流程图与状态图、目录结构优化及业务场景结合说明,帮助开发者深入理解 Semaphore 的原理与最佳实践。
二、名词解释
- Semaphore(信号量):一种并发控制机制,维护一组许可,线程获取许可后方能访问资源,许可不足则阻塞等待。
- AQS(AbstractQueuedSynchronizer):Java 并发包的同步器抽象,底层队列与状态管理基石。
- 公平/非公平模式:公平模式下,线程按先来先服务顺序获取许可;非公平模式则允许插队,提高吞吐但可能导致饥饿。
- 许可(Permit):信号量的核心资源,代表可用访问次数。
三、项目背景与发展历史
Semaphore 作为并发控制的经典方案,最早由 Dijkstra 在 1965 年提出,成为操作系统与并发编程领域的基础工具。Java 在 JDK 1.5 引入了 java.util.concurrent 并发包,Semaphore 随之成为标准库成员。
- 权威资料参考:
- Dijkstra, E. W. (1965). “Cooperating Sequential Processes”.
- Doug Lea, “Concurrent Programming in Java: Design Principles and Patterns”, Addison Wesley, 2000.
- 《Java 并发编程实战》(Brian Goetz 等著)
- JDK Semaphore 官方文档
四、源码注释与主接口梳理
1. 核心源码详解
/**
* Semaphore 并发信号量控制类
* 用于限制指定数量线程同时访问共享资源
*/
public class Semaphore {
// 内部同步器,基于 AQS 实现
private final Sync sync;
/**
* 构造方法
* @param permits 初始许可数量
* @param fair 是否公平模式(true: 先来先服务)
*/
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
/**
* 获取许可(阻塞直到获得)
* @throws InterruptedException 可响应中断
* 关键逻辑:原子减 state,许可不足则入队列阻塞
* 速记口诀:获取原子减,阻塞入队列
*/
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
/**
* 释放许可
* 关键逻辑:原子加 state,唤醒阻塞队列线程
* 速记口诀:释放原子加,唤醒重试获
*/
public void release() {
sync.releaseShared(1);
}
/**
* 查询当前可用许可数
* @return 当前剩余许可
*/
public int availablePermits() {
return sync.getPermits();
}
// ...其他方法省略
}
主流程接口梳理
| 接口/类 | 作用说明 | 调用顺序 | 备注 |
|---|---|---|---|
| Semaphore | 信号量主入口类,管理许可和同步队列 | ① | 提供 acquire/release 等主流程接口 |
| acquire() | 获取许可,阻塞直到成功 | ② | 限流入口,常用于资源访问前 |
| release() | 释放许可,唤醒阻塞线程 | ③ | 资源访问结束时调用 |
| availablePermits() | 查询当前剩余许可数 | 任意 | 可用于监控与业务限流判断 |
| Sync/FairSync/NonfairSync | 内部同步器,管理许可和队列状态 | 内部 | 继承 AQS,负责底层同步机制 |
五、结构化流程图解读
1. 主流程结构优化(flowchart)
flowchart TD
A[初始化 Semaphore] --> B[线程请求 acquire]
B --> C{许可是否足够?}
C -- 是 --> D[许可减1,进入临界区]
C -- 否 --> E[入队列阻塞]
D --> F[执行任务]
F --> G[release 释放许可]
G --> H[许可加1,唤醒队列线程]
H --> B
E --> H
简化说明:
- 初始化 Semaphore,设定最大并发数
- 线程获取许可,不足则自动排队阻塞
- 任务结束释放许可,自动唤醒队列
2. 状态流转优化(stateDiagram-v2)
简化说明:
- 线程状态在“等待许可”、“执行任务”、“队列阻塞”、“被唤醒”之间流转
- 资源释放后,阻塞线程被唤醒重新竞争许可
3. 关键交互序列图优化(sequenceDiagram)
简化说明:
- 线程获取许可时,Semaphore 判断是否足够
- 不足则队列挂起,释放后自动唤醒重试
六、目录结构优化建议
推荐目录结构如下:
src/
main/
java/
com/example/semaphore/
Semaphore.java // 主流程入口类,核心信号量实现
Sync.java // 内部同步器,AQS封装
FairSync.java // 公平同步器实现
NonfairSync.java // 非公平同步器实现
SemaphoreTest.java // 单元测试/示例
utils/
ThreadUtils.java // 通用线程工具
resources/
application.properties // 配置文件
docs/
Semaphore原理与应用.md // 核心原理文档
diagrams/ // 流程图/状态图/序列图
- 主流程入口:Semaphore.java
- 同步队列管理:Sync、FairSync、NonfairSync
- 单元测试/示例:SemaphoreTest.java
- 工具模块:utils 目录
- 文档与流程图:docs 目录,便于团队协作与知识沉淀
七、业务场景结合说明
1. 连接池限流
// 获取数据库连接前,限流保护
try {
semaphore.acquire(); // 限流入口,防止连接数超标
Connection conn = pool.getConnection();
// ...业务处理
} finally {
semaphore.release(); // 释放许可,允许后续线程获取连接
}
2. 接口限流
// API高并发限流
semaphore.acquire(); // 限流入口,超限自动排队
// 处理请求
semaphore.release(); // 释放许可,唤醒阻塞线程
3. 分布式任务调度
每台机器最多并发 50 个爬虫任务,Semaphore(50) 控制线程数量,保障带宽与资源。
八、速记口诀与系统性认知总结
Semaphore 速记口诀
- 初始化设许可:根据资源上限,准确配置许可数
- 获取原子减:每次访问资源前,原子性扣减许可
- 阻塞入队列:超限自动排队,避免资源争抢
- 释放原子加:资源释放后,原子性恢复许可
- 唤醒重试获:唤醒阻塞线程,公平竞争许可
系统性认知:
Semaphore 是并发限流的基石。知其然,需理解源码与流程。知其所以然,需结合 AQS 队列、主流程接口、状态流转与实际业务场景。通过流程图、状态图、序列图,结构化理解 Semaphore 的核心机制,能在高并发系统中合理限流、保障稳定。
九、参考文献
- Dijkstra, E. W. (1965). “Cooperating Sequential Processes”.
- Doug Lea, “Concurrent Programming in Java: Design Principles and Patterns”, Addison Wesley, 2000.
- Brian Goetz 等, 《Java 并发编程实战》
- JDK Semaphore 官方文档
- AQS 原理解析
知其然,更要知其所以然!
通过结构化注释、流程图、目录优化、业务场景结合,Semaphore 源码更加易懂、实用、可维护。建议在实际项目中严格限流,保障系统高并发下的稳定性与性能。
更多推荐


所有评论(0)