深入解析Java并发工具:CountDownLatch与Semaphore核心区别与应用场景。掌握CountDownLatch的"一次性门闩"机制,实现多线程任务协同;了解Semaphore的"资源许可证"模式,有效控制并发访问量。本文通过王者荣耀开黑、充电桩管理等生动案例,详解两者在初始化协调、连接池管理、接口限流等场景的应用。面试必备:对比表格清晰呈现核心差异,常见追问深度剖析,助你轻松应对Java并发面试难题。附2025年最新Java面试宝典资源,提升技术实力,斩获高薪offer!
大家好,今天咱们来聊聊面试中高频出现的并发工具:CountDownLatch 和 Semaphore。这两个家伙都属于java.util.concurrent包里的“利器”,名字听着唬人,但理解了机制其实很清晰。面试官最爱问它们的区别和适用场景,搞明白了,能让你在并发题上轻松过关!

2025年Java面试宝典重磅分享:
链接: https://pan.baidu.com/s/1RUVf75gmDVsg8MQp4yRChg?pwd=9b3g 提取码: 9b3g
想象一个场景:你组织了一场王者荣耀开黑,需要等5个队友都确认“准备好了”,才能一起点“开始匹配”。CountDownLatch 干的就是这个协调的活儿!
new CountDownLatch(5))。每当一个任务完成,就调用countDown(),计数器减1。调用await()的线程(比如主线程)会阻塞,直到计数器减到0才放行。await()会立刻放行,无法重置复用。想再用?new一个新的。await(),等待一组工作线程完成任务(调用countDown())。countDownLatch.countDown()作为发令枪)// 伪代码口述思路:
// 1. main线程创建CountDownLatch(5)
// 2. 启动5个工作线程,每个线程干完活就latch.countDown()
// 3. main线程调用latch.await(),等5个都完成
// 4. 5个都countDown后,main线程解除阻塞,继续执行汇总逻辑
再想象一个场景:小区里只有3个充电桩,却有10辆电动车要充电。Semaphore 就是管理这3个充电桩的“物业”。
new Semaphore(3))。线程想访问共享资源,必须先调用acquire()申请一个许可证(如果没有空闲的,线程就阻塞等待)。用完后,必须调用release()归还许可证,以便其他线程使用。release()增加许可(虽然不常用),也可以通过构造方法或reducePermits减少(需小心)。Semaphore和线程池,它们都能限制并发数,区别在哪?”(线程池管理的是工作线程本身的生命周期和任务队列;Semaphore只控制并发访问资源的入口数量,不管理线程。)// 伪代码口述思路(连接池):
// 1. 初始化Semaphore(10) // 假设10个连接
// 2. 线程想获取连接:先semaphore.acquire() // 申请许可证,没许可证就等
// 3. 拿到许可证后,从池里取一个真实连接用
// 4. 用完连接,放回池里
// 5. 调用semaphore.release() // 归还许可证,让其他线程能用

| 特性 | CountDownLatch | Semaphore |
| :----------- | :-------------------------- | :---------------------------- |
| 核心目的 | 等待事件完成 | 控制并发访问资源量 |
| 计数器 | 减到0触发 | 许可证数量 (>=0) |
| 重置性 | 不可重置 (一次性) | 可复用 (acquire/release) |
| 修改方向 | 只能减 (countDown) | 可增 (release) 可减 (acquire) |
| 主要用法 | 主线程 await() 等子线程 | 工作线程自己 acquire/release |
| 典型场景 | 初始化协调、多任务结果汇总 | 连接池、资源池、限流 |
简单记:
CountDownLatch是“等大家干完活开会”;Semaphore是“名额有限,先到先得,用完归还”。
CountDownLatch 能代替 join() 吗?为什么更好?
join() 更灵活,join()必须等线程结束,CountDownLatch只要任务完成就能countDown(),线程不一定结束。而且可以等待多个不同的线程组。Semaphore 的 acquire() 和 release() 数量必须严格匹配吗?
acquire() 多了:许可证变负数,后续线程阻塞,可能死锁。release() 多了:许可证总数变多,可能超过你期望的限制,导致过度并发。切记在finally块中释放!怎么用 Semaphore 实现互斥锁 (Mutex)?
Semaphore(1)。acquire()相当于lock(),release()相当于unlock()。这就是一个非公平的互斥锁。CyclicBarrier 和 CountDownLatch 有啥区别?
CountDownLatch:主等子,一次性,计数器单向减。CyclicBarrier:子等子(所有线程互相等),可循环使用(reset()),计数器内部重置,到达屏障点可以执行一个可选任务(Runnable)。被问到区别时,不要死背概念。结合具体例子:
“CountDownLatch 就像火箭发射前的检查,要等所有系统(引擎、导航、通信…)都回报‘Ready’(
countDown()),总控台(await())才点火发射。是一次性的协作。Semaphore 更像停车场入口的闸机,总共50个车位(
permits=50)。车来了要拿卡(acquire())才能进,没卡等;车走了要还卡(release())让别的车进。它控制的是同时停车的数量,闸机(Semaphore)可以一直用。”

用好并发工具,写出高效稳定的代码是面试加分项! 如果你正在准备面试,需要系统刷题和深入理解Java并发,可以考虑购买面试鸭会员获取海量真题解析和深度资料。对了,通过 面试鸭返利网 (mianshiyafanli.com) 找我购买,还能享受 25元返利 哦!
理解清楚 CountDownLatch 和 Semaphore 的设计思想和适用场景,下次遇到并发协调问题,你就能快速选出最合适的工具了!加油!
扫码联系我返利
(当前返利8元,金额随官方实际价格波动,最好提前咨询)

面试鸭小程序码

美团大额优惠券,给自己加个鸡腿吧!

支付宝扫码领取1-8元无门槛红包
