semaphore 的权限获取机制本质是“许可计数 + 阻塞等待”的组合,通过原子减法(acquire)和加法(release)操作 state 计数器控制并发数,支持公平/非公平模式、超时获取及误释放防护。

Semaphore 的权限获取机制本质是“许可计数 + 阻塞等待”的组合,它不锁住代码,而是控制能进入临界区的线程数量。关键不在“谁先拿到”,而在“当前还剩几个名额”。
许可数量决定并发上限
构造时传入的 permits 值就是系统允许的最大并发数,也是内部计数器的初始值。这个数一旦设定,就定义了资源池的容量边界:
- 设为 1 → 效果等同互斥锁(但语义不同,不强调所有权)
- 设为 5 → 最多 5 个线程可同时执行受保护逻辑
- 设为 0 → 所有 acquire() 调用立即阻塞,适合做“启动门控”
acquire() 是减法操作,不是排队登记
每次调用 acquire(),底层 AQS 尝试对 state(即剩余许可数)执行原子减 1。成功则继续执行;失败(state 变为负数)才真正进入同步队列等待:
- 非公平模式:新线程和唤醒线程一起竞争,可能“插队”
- 公平模式:严格按 FIFO 排队,先到先得,避免饥饿但吞吐略低
- acquire(3) 表示一次性扣减 3 个许可,要求当前可用数 ≥ 3,否则整体阻塞
release() 是加法唤醒,不校验调用者身份
release() 只做一件事:给 state 加 1,并检查是否有等待线程。若有,唤醒一个(公平模式唤醒队首,非公平模式可能唤醒任意一个):
- 不要求释放者必须是获取者——任何线程都能 release,适合异步场景(如回调释放)
- release(2) 表示归还 2 个许可,state 增加 2,可能唤醒多个等待线程(取决于队列长度与许可增量)
- 误调用 release 多次会导致许可数溢出,超出初始值,可能引发逻辑失控(需业务层防护)
超时与尝试获取提供柔性控制
硬阻塞(acquire())在高 SLA 场景中风险较高,推荐搭配以下方式提升健壮性:
- tryAcquire():非阻塞,返回 true/false,适合快速失败策略
- tryAcquire(2, 1, TimeUnit.SECONDS):最多等 1 秒,期间若获得 2 个许可则返回 true,否则 false
- 结合 availablePermits() 可做预检,但注意该值瞬时有效,不能替代 acquire 的原子性











