Semaphore是协调资源使用的规则制定者,通过动态许可计数(acquire减、release加)控制并发数,支持公平/非公平模式,适用于连接池、限流等场景,需配对调用并避免阻塞滥用。

Semaphore信号量不是用来“抢”资源的,而是用来协调资源使用的规则制定者。它不制造争抢,而是把争抢转化为有序排队——核心思想是用许可(permits)代替竞争,用计数控制代替无序抢占。
许可机制:用数字管住并发线程
信号量内部维护一个整数计数器,代表当前可用的许可数量。这个数不是固定不变的,而是在 acquire 和 release 之间动态流转:
- 每次调用 acquire(),计数器减1;如果减完后为负,线程就停在门口等待
- 每次调用 release(),计数器加1;如果有线程在等,就唤醒一个继续执行
- 初始值即最大并发数,比如 new Semaphore(5) 表示最多5个线程能同时进入临界区
公平性选择:先到先得还是快速响应
创建信号量时可指定是否启用公平模式,这直接影响线程获取许可的顺序:
- 非公平(默认):新来的线程可能直接插队获取许可,吞吐更高,但等待久的线程可能被反复跳过
- 公平:严格按等待时间排序,老线程优先,避免饥饿,但上下文切换略多、性能稍低
- 适用场景举例:对响应延迟敏感的服务(如API网关)常用非公平;金融类强一致性场景倾向公平
典型资源管控场景
信号量的价值体现在它能把抽象的“资源紧张”转化为可配置、可监控的具体数值:
- 数据库连接池:设 permits = 最大连接数,防止连接耗尽导致服务雪崩
- 第三方接口调用:按服务商限流阈值设 permits,避免触发熔断或封禁
- 文件批量读写:限制同时打开的文件句柄数,避开操作系统级限制(如Linux默认1024)
- 硬件设备访问:如打印机、传感器,确保同一时刻仅有限数量线程操作物理设备
常见误用与规避要点
信号量本身简单,但用错会导致泄漏、死锁或形同虚设:
- 必须配对使用 acquire 和 release,尤其在异常路径中要用 finally 块保障 release 执行
- 避免在持有许可期间做长时间阻塞操作(如远程调用未设超时),否则许可长期被占,其他线程无限等待
- 不要把信号量当锁用:它不保证临界区互斥,只控制并发数;多个线程拿到许可后仍需自行处理数据一致性
- permits 数量要结合系统容量设定——太小造成大量等待,太大失去限流意义

















