Java 并发工具 Semaphore 全面解析与实用案例
·
Java 并发工具 Semaphore 全面解析与实用案例
一、概述
在高并发场景下,如何有效地限制资源访问数量、实现“限流”是开发者常见的需求。Java 并发包 java.util.concurrent 提供了多种工具,其中 Semaphore(信号量)就是一种非常实用的资源访问控制器。它能够限制某一类资源被同时访问的线程(或进程)数量,广泛用于连接池、限流、停车场等场景。
二、名词解释
- Semaphore(信号量):一种同步工具,用于控制同时访问某特定资源的操作数量。
- 许可(Permit):Semaphore 内部维护的计数,每个线程获取资源时需要申请许可,许可用完则阻塞等待。
- 公平性(Fairness):Semaphore 支持公平/非公平模式,公平模式下资源按照请求顺序分配,非公平则可能插队。
三、发展历史与权威资料
- 最早的信号量概念由 Edsger Dijkstra 在 1965 年提出,作为进程同步的基础机制。
- Java 1.5 引入了
java.util.concurrent.Semaphore,极大方便了多线程资源控制。 - 参考资料:
四、项目背景与应用场景
现实中的资源访问常被限制,比如:
- 数据库连接池:同时连接的线程数量有限,超过时需等待。
- 停车场:车位有限,满员后新车需等待。
- 限流服务:API 请求量达上限时拒绝或排队处理。
这些场景都需要一种机制来“限流”,Semaphore 就是最佳选择之一。
五、Semaphore 核心用法与重要方法
1. 构造方法
// 创建具有指定许可数的非公平 Semaphore
Semaphore(int permits);
// 创建具有指定许可数和公平设置的 Semaphore
Semaphore(int permits, boolean fair);
2. 重要方法详解
acquire()/acquire(int permits):获取许可,资源不足则阻塞。release()/release(int permits):释放许可,唤醒等待线程。availablePermits():当前可用许可数。reducePermits(int reduction):减少许可数(谨慎使用)。hasQueuedThreads():是否有线程在等待资源。getQueueLength():大致等待线程数。tryAcquire(int permits, long timeout, TimeUnit unit):超时尝试获取许可。acquireUninterruptibly(int permits):不可中断地获取许可。
六、实战案例 —— 餐厅打饭窗口
背景
假设餐厅有 3 个打饭窗口,学生排队打饭。每次最多只有 3 个学生可以同时打饭。
核心代码
1. Semaphore 控制窗口数量
Semaphore windowSemaphore = new Semaphore(3); // 3 个窗口
2. 学生线程模拟
class Student implements Runnable {
private Semaphore semaphore;
private String name;
public Student(Semaphore semaphore, String name) {
this.semaphore = semaphore;
this.name = name;
}
@Override
public void run() {
try {
System.out.println(name + " 申请窗口许可...");
semaphore.acquire();
System.out.println(name + " 正在打饭...");
Thread.sleep(3000); // 模拟打饭
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
System.out.println(name + " 打饭结束,释放窗口许可");
}
}
}
3. 测试主程序
public class Test {
public static void main(String[] args) {
Semaphore windowSemaphore = new Semaphore(3);
for (int i = 1; i <= 8; i++) {
new Thread(new Student(windowSemaphore, "学生" + i)).start();
}
}
}
实际效果
同一时刻只允许 3 个学生打饭,其他学生自动排队等待。
七、原理剖析与与 synchronized 区别
synchronized 用于保证“同步”,即临界区同一时刻只有一个线程访问。而 Semaphore 是“互斥/限流”,可以设置同时允许多个线程访问某资源,但超过数量则阻塞。
- 同步:保证顺序与一致性。
- 互斥/限流:保证资源数量不被超用。
八、速记口诀
“信号量限流,许可来分流;资源有限制,排队等候用。”
九、结构图解
1. Flowchart:资源申请与释放流程
flowchart TD
A(学生请求窗口) --> B{窗口许可是否足够?}
B -- 是 --> C[获得许可,开始打饭]
B -- 否 --> D[等待]
C --> E[打饭结束]
E --> F[释放窗口许可]
D --> B
2. State Diagram:学生打饭状态变化
3. Sequence Diagram:多个学生与窗口的交互
十、总结与参考资料
- Semaphore 是限流的理想工具,适用于资源有数量限制的场景;
- 与 synchronized 区别显著:Semaphore 是“限流”,synchronized 是“同步”;
- 关键速记:“信号量限流,许可来分流;资源有限制,排队等候用。”
- 推荐进一步阅读权威书籍和官方文档。
参考文献
结语
只要掌握了 Semaphore 的原理和用法,无论是限流、连接池还是停车场问题,都可以优雅高效地解决。希望本篇图文并茂的技术博客能让你“知其然,更知其所以然”。
更多推荐

所有评论(0)