【锁3】Semaphore(信号量)
📅 2026/8/1 14:21:03
👁️ 阅读次数
📝 编程学习
Semaphore(信号量)的核心是用 N 张“许可证”限制同时访问资源的线程数——线程进来先 acquire() 拿一张,用完 release() 还回去;许可证发完了,后面的线程就得排队。下面给你 Java 最常用版本的可运行示例。
核心概念
初始化时指定许可证数量 N,相当于“最多允许 N 个线程同时进临界区”
acquire():拿许可证,没有就阻塞等待
release():还许可证,务必放在finally或使用with,否则忘了释放就会死锁
tryAcquire():非阻塞版本,拿不到立刻返回false,适合做限流降级
importjava.util.concurrent.Semaphore;publicclassSemaphoreDemo{// 许可证数量为 3,即同时最多 3 个线程能进临界区privatestaticfinalSemaphoresemaphore=newSemaphore(3);publicstaticvoidmain(String[]args){for(inti=1;i<=5;i++){newThread(newTask("线程-"+i)).start();}}staticclassTaskimplementsRunnable{privatefinalStringname;Task(Stringname){this.name=name;}@Overridepublicvoidrun(){try{semaphore.acquire();// 拿许可证,没有就阻塞System.out.println(name+" 进入临界区,当前可用许可证: "+semaphore.availablePermits());Thread.sleep(2000);// 模拟业务耗时System.out.println(name+" 执行完毕");}catch(InterruptedExceptione){e.printStackTrace();}finally{semaphore.release();// 一定要释放!System.out.println(name+" 释放许可证");}}}}运行后会看到:前 3 个线程同时进入,后 2 个等前面有人释放后才依次进入。
线程-1 进入临界区,当前可用许可证:2线程-4 进入临界区,当前可用许可证:0线程-3 进入临界区,当前可用许可证:1线程-1 执行完毕 线程-4 执行完毕 线程-3 执行完毕 线程-4 释放许可证 线程-3 释放许可证 线程-1 释放许可证 线程-5 进入临界区,当前可用许可证:1线程-2 进入临界区,当前可用许可证:2线程-5 执行完毕 线程-5 释放许可证 线程-2 执行完毕 线程-2 释放许可证 进程已结束,退出代码为0🎯 典型应用场景对比
| 场景 | 许可证数量 | 说明 |
|---|---|---|
| 数据库连接池 | 连接数上限 | 例如设置 10,防止连接耗尽 |
| API 接口限流 | QPS 上限 | 例如设置 50,保护后端服务 |
| 爬虫并发控制 | 目标站承受力 | 避免请求过快被封 IP |
| 互斥锁(Mutex)* | 1 | 等同于Lock,实现线程独占 |
⚠️ 注意事项
- 死锁风险:如果
acquire()后未调用release()(如异常中断),会导致永久阻塞。 - 公平性:Java 构造器
new Semaphore(3, true)可设置为公平模式(FIFO),但会降低性能。 - Asyncio 作用域:
asyncio.Semaphore必须在async def函数内创建,不能在模块顶层创建(会报 Event Loop 错误)。
编程学习
技术分享
实战经验