CountDownLatch、CyclicBarrier、Semaphore

Posted by ivan on 2025-03-20 22:34:33
 浏览量:928 最近编辑于:2025-03-20 22:34:33

CountDownLatch

作用:
用于让一个或多个线程等待其他线程完成操作后再继续执行。
通过一个计数器(count)来实现,计数器的初始值由构造方法指定。
每当一个线程完成任务后调用 countDown(),计数器减 1,当计数器减为 0 时,所有等待的线程会被唤醒。
常见场景:
主线程等待多个子线程完成任务。
模拟并发测试,确保多个线程同时开始执行

  1. import java.util.concurrent.CountDownLatch;
  2. public class CountDownLatchExample {
  3. public static void main(String[] args) throws InterruptedException {
  4. int threadCount = 3;
  5. CountDownLatch latch = new CountDownLatch(threadCount);
  6. for (int i = 0; i < threadCount; i++) {
  7. new Thread(() -> {
  8. try {
  9. System.out.println(Thread.currentThread().getName() + " is working...");
  10. Thread.sleep(1000); // 模拟任务执行
  11. System.out.println(Thread.currentThread().getName() + " finished.");
  12. } catch (InterruptedException e) {
  13. e.printStackTrace();
  14. } finally {
  15. latch.countDown(); // 计数器减 1
  16. }
  17. }).start();
  18. }
  19. System.out.println("Main thread is waiting...");
  20. latch.await(); // 等待计数器减为 0
  21. System.out.println("All threads have finished. Main thread continues.");
  22. }
  23. }

CyclicBarrier

作用:
用于让一组线程互相等待,直到所有线程都到达某个屏障点(barrier)后再继续执行。
与 CountDownLatch 的区别是,CyclicBarrier 可以重复使用,而 CountDownLatch 只能使用一次。
常见场景:
多线程分阶段执行任务,所有线程在每个阶段都需要同步。

  1. import java.util.concurrent.BrokenBarrierException;
  2. import java.util.concurrent.CyclicBarrier;
  3. public class CyclicBarrierExample {
  4. public static void main(String[] args) {
  5. int threadCount = 3;
  6. CyclicBarrier barrier = new CyclicBarrier(threadCount, () -> {
  7. System.out.println("All threads have reached the barrier. Proceeding to the next step...");
  8. });
  9. for (int i = 0; i < threadCount; i++) {
  10. new Thread(() -> {
  11. try {
  12. System.out.println(Thread.currentThread().getName() + " is working...");
  13. Thread.sleep(1000); // 模拟任务执行
  14. System.out.println(Thread.currentThread().getName() + " reached the barrier.");
  15. barrier.await(); // 等待其他线程到达屏障
  16. } catch (InterruptedException | BrokenBarrierException e) {
  17. e.printStackTrace();
  18. }
  19. }).start();
  20. }
  21. }
  22. }

Semaphore

作用:
用于控制同时访问某个资源的线程数量。
通过信号量(permits)限制资源的并发访问数量。
常见场景:
限制对某些资源(如数据库连接、文件等)的并发访问。
实现限流。

  1. import java.util.concurrent.Semaphore;
  2. public class SemaphoreExample {
  3. public static void main(String[] args) {
  4. int permits = 2; // 允许同时访问的线程数
  5. Semaphore semaphore = new Semaphore(permits);
  6. for (int i = 0; i < 5; i++) {
  7. new Thread(() -> {
  8. try {
  9. System.out.println(Thread.currentThread().getName() + " is trying to acquire a permit...");
  10. semaphore.acquire(); // 获取许可
  11. System.out.println(Thread.currentThread().getName() + " acquired a permit.");
  12. Thread.sleep(2000); // 模拟任务执行
  13. System.out.println(Thread.currentThread().getName() + " is releasing a permit.");
  14. } catch (InterruptedException e) {
  15. e.printStackTrace();
  16. } finally {
  17. semaphore.release(); // 释放许可
  18. }
  19. }).start();
  20. }
  21. }
  22. }

总结

工具 作用 常见场景
CountDownLatch 让一个或多个线程等待其他线程完成任务后再继续执行。 主线程等待多个子线程完成任务,模拟并发测试。
CyclicBarrier 让一组线程互相等待,直到所有线程都到达屏障点后再继续执行。 多线程分阶段执行任务,所有线程在每个阶段都需要同步。
Semaphore 控制同时访问某个资源的线程数量。 限制对资源的并发访问(如数据库连接池、限流)。
区别:
CountDownLatch:
一次性使用,计数器减到 0 后不能重置。
适用于主线程等待子线程完成任务的场景。
CyclicBarrier:
可重复使用,适用于多线程分阶段同步的场景。
提供一个可选的 Runnable,在所有线程到达屏障点时执行。
Semaphore:
用于控制并发访问的线程数量。
适用于限流或资源池管理的场景。








评论