Java中的CountDownLatch、CyclicBarrier和Semaphore详解
字数 1539 2025-11-06 12:41:12
Java中的CountDownLatch、CyclicBarrier和Semaphore详解
1. 基本概念与作用
CountDownLatch、CyclicBarrier和Semaphore是JUC包中常用的同步工具类,用于协调多线程之间的执行顺序或资源分配:
- CountDownLatch:允许一个或多个线程等待其他线程完成操作后再执行。
- CyclicBarrier:让一组线程互相等待,达到屏障点后同时继续执行,可重复使用。
- Semaphore:控制同时访问特定资源的线程数量,通过许可证(permits)实现限流。
2. CountDownLatch 详解
核心机制
- 初始化时指定一个计数器(如
new CountDownLatch(3))。 - 线程调用
countDown()时计数器减1,调用await()的线程会阻塞直到计数器归零。
使用场景
- 主线程等待多个子线程完成任务后再继续(如并行计算后汇总结果)。
- 服务启动时等待所有依赖组件初始化完成。
示例代码
CountDownLatch latch = new CountDownLatch(2);
// 子线程完成任务后递减计数器
new Thread(() -> {
System.out.println("任务1完成");
latch.countDown();
}).start();
new Thread(() -> {
System.out.println("任务2完成");
latch.countDown();
}).start();
// 主线程等待所有任务完成
latch.await();
System.out.println("所有任务完成,主线程继续");
特点:计数器不可重置,一次性使用。
3. CyclicBarrier 详解
核心机制
- 初始化时指定线程数量(如
new CyclicBarrier(3))和一个可选的屏障动作(Runnable)。 - 线程调用
await()时阻塞,直到指定数量的线程都到达屏障点,然后所有线程同时继续执行。
使用场景
- 多阶段任务需要同步(如并行计算中每阶段需等待所有线程就绪)。
- 模拟并发测试(多个线程同时触发操作)。
示例代码
CyclicBarrier barrier = new CyclicBarrier(3, () -> {
System.out.println("所有线程到达屏障,执行屏障动作");
});
for (int i = 0; i < 3; i++) {
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "到达屏障");
try {
barrier.await(); // 等待其他线程
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "继续执行");
}).start();
}
特点:计数器可重置(通过reset()方法),支持重复使用。
4. Semaphore 详解
核心机制
- 初始化时指定许可证数量(如
new Semaphore(3))。 - 线程通过
acquire()获取许可证(若无许可证则阻塞),通过release()释放许可证。
使用场景
- 限制资源并发访问数(如数据库连接池、接口限流)。
- 控制线程池中任务提交速率。
示例代码
Semaphore semaphore = new Semaphore(2); // 允许2个线程同时访问
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
semaphore.acquire(); // 获取许可证
System.out.println(Thread.currentThread().getName() + "占用资源");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release(); // 释放许可证
System.out.println(Thread.currentThread().getName() + "释放资源");
}
}).start();
}
特点:支持公平/非公平模式,许可证可动态增减。
5. 三者的对比
| 特性 | CountDownLatch | CyclicBarrier | Semaphore |
|---|---|---|---|
| 计数器是否可重置 | 否(一次性) | 是(可重复使用) | 是(许可证可回收) |
| 核心作用 | 等待其他线程完成 | 线程间相互等待 | 控制资源访问数量 |
| 调用方法 | await()/countDown() |
await() |
acquire()/release() |
| 适用场景 | 主从协作 | 多阶段同步 | 资源池、限流 |
6. 注意事项
- CountDownLatch的
await()可设置超时时间,避免无限等待。 - CyclicBarrier的屏障动作由最后到达屏障的线程执行。
- Semaphore的
release()方法可在任意线程调用,即使未先调用acquire()(可能导致许可证数量超过初始值)。
通过合理选择这三种工具,可以高效解决线程同步和资源控制问题。