Semaphore 适合控制“同时在线用户数”等有明确上限的资源访问,通过 permits 机制限制并发线程数,如 new Semaphore(100) 表示最多 100 人在线,登录 acquire、登出 release,配合超时、监控与异常处理实现可靠限流。

核心思路:用 permits 表示可用的在线名额
初始化一个 Semaphore(最大在线数),比如允许最多 100 人同时在线,就 new Semaphore(100)。用户登录时尝试获取一个许可(acquire),成功即视为“上线”;登出或会话超时时释放该许可(release),腾出名额给新用户。超出限额的登录请求会被阻塞或快速失败,避免系统过载。
典型实现方式
实际开发中建议封装为服务类,配合 Spring 等框架使用:
-
初始化信号量:在配置类或 Bean 中声明,例如
private final Semaphore onlineLimit = new Semaphore(100, true);(true 表示公平模式,避免饥饿) -
登录逻辑:调用
onlineLimit.tryAcquire(1, 3, TimeUnit.SECONDS)尝试获取许可,带超时防止无限等待;返回 true 才允许建立会话,否则返回“系统繁忙” -
登出/超时清理:无论成功与否,只要曾占用名额,就必须在 finally 块或拦截器中调用
onlineLimit.release() -
监控与告警:可通过
onlineLimit.getQueueLength()获取当前排队等待的请求数,结合availablePermits()判断剩余容量,触发阈值告警
注意边界与异常情况
单纯靠 acquire/release 不能完全等同于“真实在线用户数”,需额外保障:
- 用户关闭浏览器未主动登出 → 需搭配 Session 过期监听或定时任务,自动 release
- 服务重启导致计数丢失 → 若需持久化状态,应结合 Redis 等外部存储做分布式限流(此时 Semaphore 仅适用于单机场景)
- 重复登录覆盖旧会话 → 应在业务层保证单点登录逻辑,Semaphore 只负责“并发数”控制,不处理身份唯一性
和其它方案的区别
不同于 synchronized 或 ReentrantLock(只保证互斥,不控制数量),也不同于 CountDownLatch(一次性倒计时),Semaphore 天然支持“动态配额+多次进出”。它不关心谁来了、谁走了,只统计当前持有许可的线程数——这恰恰契合“在线用户数”作为纯数量指标的本质。
立即学习“Java免费学习笔记(深入)”;



















