嗨!大家好,我是你们熟悉的 31 岁程序员小米,一个喜欢写代码、讲故事、做饭、撸猫、写公众号的人。
今天这篇文章,咱们继续讲点面试中高频但是常被忽视的 Java 多线程知识点。最近我一个老同事去面试,HR 问了个看似简单但实际很多人讲不清楚的问题:
Semaphore 有什么作用?它和锁有什么区别?能不能举个生活里的例子说明一下?
老同事回来跟我吐槽:“小米啊,我平时用 synchronized、ReentrantLock 用得顺溜,轮到 Semaphore 就懵圈,面试时候只说出是‘限流’用的,面试官明显不满意。”
好家伙,咱这不行啊。
既然如此,今天我就跟大家唠个透彻,顺便给正在准备社招的小伙伴打打鸡血,整理一波知识点!
Semaphore 是个啥玩意?咱先别忙着看代码,先来点接地气的故事。
故事时间:小米去健身房抢跑步机
我最近开始减肥,报名了个健身房。健身房里有 5 台跑步机,大家都可以去跑,但总不能无限人一起跑对吧,最多只能同时用 5 台。
如果我去的时候,跑步机还有空位,我就可以上去开跑;如果 5 台都被人用了,我只能等着,等有个人跑完下来,释放一台跑步机,我再上去跑。
跑步机 = 资源
排队的人 = 线程
健身房规则 = Semaphore 控制
Semaphore 的作用就像健身房里的“跑步机空位指示灯”:
5 个指示灯亮着,说明还能进 5 个;
灭了,说明得等,有人下来才有空。
总结一句话:Semaphore 是一个计数器,控制同时访问某个特定资源的线程数量。
Semaphore 怎么用?咱这就来写段 Java 代码,把健身房的场景搬进代码里
核心方法:
Semaphore.acquire():申请一个许可,如果没有就阻塞等待。
Semaphore.release():释放一个许可,让其他线程继续抢。
这样就实现了最多 5 个人同时用跑步机。
和 synchronized、ReentrantLock 有啥区别?很多朋友一看 Semaphore,心里就犯嘀咕:“我用 synchronized 不也能保证线程安全吗?ReentrantLock 也行啊,干嘛还搞个 Semaphore?”
咱来对比下
也就是说:
synchronized、ReentrantLock 是“互斥锁”,一次只允许一个线程进入。
Semaphore 更灵活,允许多个线程同时访问,但数量有限制。
这也是为什么很多限流场景、连接池、资源池管理里,Semaphore 是首选。
常见使用场景面试答题最忌空泛,一定得举例子,实打实。
我来整理一下工作中常用的 5 个场景:
1. 限流
比如一个接口最多允许 10 个并发请求,超过的排队。
每个请求到来先 acquire(),走完逻辑 release()。
2. 资源池管理
比如数据库连接池、线程池,最多给定数量的资源,控制并发数量。
3. 多线程限量执行
比如有 50 个线程,但我只希望最多 5 个一起干活,干完一批,再放下一批。
4. 生产者-消费者模型
比 synchronized 更灵活地控制消费者数量。
5. 实现死锁演示
如果 acquire() 顺序写反,就很容易模拟死锁。
延伸知识:Semaphore 怎么实现的?如果你对底层好奇,咱简单说下。
Semaphore 本质上是基于 AQS(AbstractQueuedSynchronizer) 实现的。
核心变量:
而 Sync 里维护了一个 state 值,表示可用许可证数量。
acquire() 其实是尝试把 state--,如果小于 0 就排队阻塞。
release() 则是 state++,然后唤醒队列里的线程。
是不是感觉和锁有点类似?没错,AQS 就是个超强的同步框架,ReentrantLock、CountDownLatch、Semaphore 都是基于它。
面试答题模板最后,我来给大家写个标准答题模板,方便社招面试时候用。
题目:Semaphore 有什么作用?和锁有什么区别?举个例子说明。
答:
Semaphore 是一个用于控制同时访问某个特定资源的线程数量的同步工具。它内部维护一个许可证计数器,每个线程在访问资源前需要先获取许可,访问结束后再释放许可。
和锁(synchronized / ReentrantLock)相比,锁是排他锁,一次只允许一个线程访问资源,而 Semaphore 可以同时允许多个线程访问,数量由许可数决定,更适合限流、资源池管理、连接池等场景。
举个例子,比如健身房有 5 台跑步机,最多允许 5 个人同时使用,Semaphore 就相当于跑步机的空位计数器,满了就得等,空了就能上。
写在最后兄弟姐妹们,看完这篇,是不是觉得 Semaphore 没那么神秘了?
其实很多面试题,关键在于你能不能讲清楚它在实际生活/工作中的作用,而不是光背 API。
我这次用健身房跑步机的例子,希望能帮你把这个概念记牢。如果觉得有用,别忘了点个“在看” 和 “转发”支持一下!
END你们要是感兴趣,下期我来写:
CountDownLatch 和 CyclicBarrier 的区别
Java 多线程限流实战
手撸线程池
咱们下期见!小米敬上~