Java 并发工具类:CountDownLatch、CyclicBarrier、Semaphore 详解

Java 并发工具类:CountDownLatch、CyclicBarrier、Semaphore 详解

一、引言

在 Java 的并发编程中,为了更方便地协调多个线程的执行,java.util.concurrent 包提供了一些实用的并发工具类。其中,CountDownLatchCyclicBarrierSemaphore 是三个常用的工具类,它们各自有着独特的功能和应用场景。

二、CountDownLatch

2.1 简介

CountDownLatch 是一个同步辅助类,它允许一个或多个线程等待其他线程完成操作。其内部维护了一个计数器,该计数器的初始值由构造函数指定,每当一个线程完成任务后,会调用 countDown() 方法将计数器减 1,当计数器的值变为 0 时,等待在 await() 方法上的线程将被唤醒继续执行。

2.2 主要方法

  • CountDownLatch(int count):构造函数,初始化计数器的值。
  • void countDown():将计数器的值减 1,当计数器变为 0 时,释放所有等待的线程。
  • void await():使当前线程等待,直到计数器的值变为 0。
  • boolean await(long timeout, TimeUnit unit):使当前线程等待,直到计数器的值变为 0 或等待超时。

2.3 示例代码

import java.util.concurrent.CountDownLatch;

public class CountDownLatchExample {
    public static void main(String[] args) throws InterruptedException {
        int workerCount = 3;
        CountDownLatch latch = new CountDownLatch(workerCount);

        for (int i = 0; i < workerCount; i++) {
            final int index = i;
            new Thread(() -> {
                try {
                    System.out.println("Worker " + index + " 开始工作");
                    Thread.sleep((long) (Math.random() * 1000));
                    System.out.println("Worker " + index + " 完成工作");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    latch.countDown();
                }
            }).start();
        }

        System.out.println("主线程等待所有工作线程完成...");
        latch.await();
        System.out.println("所有工作线程已完成,主线程继续执行");
    }
}

2.4 应用场景

  • 并行任务的汇总:多个线程同时执行不同的子任务,主线程需要等待所有子任务完成后进行汇总操作。
  • 资源初始化:多个线程负责不同资源的初始化,主线程需要等待所有资源初始化完成后才能继续执行后续操作。

三、CyclicBarrier

3.1 简介

CyclicBarrier 是一个同步辅助类,它允许一组线程相互等待,直到所有线程都到达某个公共屏障点(barrier point)。与 CountDownLatch 不同的是,CyclicBarrier 可以被重复使用,当所有线程都到达屏障点后,计数器会被重置,可以继续进行下一轮的等待。

3.2 主要方法

  • CyclicBarrier(int parties):构造函数,指定参与等待的线程数量。
  • CyclicBarrier(int parties, Runnable barrierAction):构造函数,除了指定参与等待的线程数量外,还可以指定一个在所有线程到达屏障点后执行的任务。
  • int await():使当前线程等待,直到所有线程都到达屏障点。返回值为当前线程到达屏障点的顺序。
  • int await(long timeout, TimeUnit unit):使当前线程等待,直到所有线程都到达屏障点或等待超时。

3.3 示例代码

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
    public static void main(String[] args) {
        int playerCount = 3;
        CyclicBarrier barrier = new CyclicBarrier(playerCount, () -> {
            System.out.println("所有玩家已准备好,游戏开始!");
        });

        for (int i = 0; i < playerCount; i++) {
            final int index = i;
            new Thread(() -> {
                try {
                    System.out.println("玩家 " + index + " 正在准备...");
                    Thread.sleep((long) (Math.random() * 1000));
                    System.out.println("玩家 " + index + " 已准备好");
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

3.4 应用场景

  • 多线程并行计算:多个线程分别计算不同的数据块,当所有线程都完成计算后,再进行汇总和合并操作。
  • 游戏场景:多个玩家需要都准备好后才能开始游戏。

四、Semaphore

4.1 简介

Semaphore 是一个计数信号量,它用于控制同时访问某个资源的线程数量。Semaphore 内部维护了一个许可证(permit)的计数器,线程在访问资源前需要先获取许可证,如果许可证数量大于 0,则线程可以获取许可证并继续执行,同时许可证数量减 1;当线程使用完资源后,需要释放许可证,许可证数量加 1。

4.2 主要方法

  • Semaphore(int permits):构造函数,初始化许可证的数量。
  • Semaphore(int permits, boolean fair):构造函数,初始化许可证的数量,并指定是否使用公平锁。
  • void acquire():获取一个许可证,如果没有可用的许可证,则当前线程会被阻塞。
  • void acquire(int permits):获取指定数量的许可证,如果没有足够的许可证,则当前线程会被阻塞。
  • void release():释放一个许可证。
  • void release(int permits):释放指定数量的许可证。

4.3 示例代码

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    public static void main(String[] args) {
        int resourceCount = 2;
        Semaphore semaphore = new Semaphore(resourceCount);

        for (int i = 0; i < 5; i++) {
            final int index = i;
            new Thread(() -> {
                try {
                    semaphore.acquire();
                    System.out.println("线程 " + index + " 获得资源,开始使用");
                    Thread.sleep((long) (Math.random() * 1000));
                    System.out.println("线程 " + index + " 使用完资源,释放资源");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();
                }
            }).start();
        }
    }
}

4.4 应用场景

  • 资源限流:控制同时访问某个资源的线程数量,防止资源被过度使用。
  • 数据库连接池:限制同时使用数据库连接的线程数量。

五、总结

CountDownLatchCyclicBarrierSemaphore 是 Java 并发编程中非常实用的工具类,它们各自有着不同的功能和应用场景。CountDownLatch 适用于一个或多个线程等待其他线程完成任务的场景;CyclicBarrier 适用于一组线程相互等待到达某个公共屏障点的场景;Semaphore 适用于控制同时访问某个资源的线程数量的场景。合理使用这些工具类可以帮助我们更方便地编写高效、安全的并发程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值