信号量的permit是可复用的通行券,本质为无状态许可计数器,依赖AQS的state字段和CAS实现线程安全增减;公平性仅影响等待线程获取顺序,非公平模式默认吞吐更高。

信号量(Semaphore)的permit管理机制,本质是一个带状态的许可计数器,它不绑定线程、不记录谁拿了许可,只管“还有几个能发”和“有没有人等着要”。它的力量恰恰来自这种轻量、无状态的设计。
permit 是什么:不是锁,是可复用的通行券
permit 不是所有权凭证,也不与线程一一对应。它更像停车场的空余车位数——车(线程)来了就减一,车走了就加一。同一个线程可以多次 acquire 和 release,甚至 acquire 两次再 release 一次(只要逻辑合理),不会报错,但可能造成 permit 泄漏或负数风险。
- 初始化时指定总数,比如 new Semaphore(5) 表示最多 5 个并发
- 每次 acquire() 尝试消耗 1 个 permit;acquire(3) 则需一次性扣减 3 个
- release() 总是增加 permit,哪怕当前没有线程在等待,也不会报错
- permit 数量可为 0,此时所有 acquire 都会阻塞,直到有人 release
permit 的增减如何保证线程安全
底层完全依赖 AQS(AbstractQueuedSynchronizer)的 state 字段和 CAS 操作。state 直接代表当前可用 permit 数。acquire 和 release 的核心就是对 state 做原子性减法或加法。
- acquire():循环 CAS 尝试将 state 从 N 变为 N−1;失败则入队等待
- release():直接 CAS 将 state 从 N 变为 N+1,并唤醒头结点等待线程
- 整个过程无需 synchronized 或 lock,靠硬件级原子指令保障一致性
公平 vs 非公平:影响的是谁拿到下一个 permit
公平性不改变 permit 总数,只改变等待线程获取许可的顺序。
- 非公平模式(默认):新线程可能插队成功,只要 state > 0 就立即抢到,吞吐高
- 公平模式:严格 FIFO,新线程必须排到队尾,等前面所有等待者都处理完才轮到自己
- 注意:公平性只在有线程排队时生效;若没人在等,两者行为完全一致
常见误用与规避建议
permit 管理看似简单,但容易因使用不当导致死锁、泄漏或逻辑错误。
- 务必在 finally 块中 release:避免因异常跳过释放,导致 permit 永久丢失
- 不要假设 acquire 成功后一定有 permit 可用:比如 tryAcquire() 返回 true 后,其他线程可能已抢先 release 并再次 acquire
- 慎用 drainPermits():它会清空所有可用 permit 并返回原值,适合做“紧急熔断”,但不适合常规控制流
- 避免跨作用域混用 permit 数量:acquire(2) 后 release(1),会导致 permit 数失衡,应保持配对或明确注释意图

















