Java中的CountDownLatch及其使用

引言

在并发编程中,我们经常会遇到这样的场景:主线程需要等待所有子线程执行完成后再执行后续操作。Java提供了CountDownLatch来解决这个问题。本文将详细介绍CountDownLatch的用法,并给出相关的代码示例。

CountDownLatch简介

CountDownLatch是Java并发包(java.util.concurrent)中的一个类,用于控制多线程并发执行的顺序。它通过一个计数器来实现,该计数器初始化为一个正整数,每当一个线程完成任务后,计数器的值就减1。当计数器的值为0时,表示所有线程都已经完成任务,此时主线程即可执行后续操作。

CountDownLatch的构造函数接收一个int类型的参数,用于指定计数器的初始值。计数器的值只能被设置一次,一旦被设置为0后,就无法再重新设置。

CountDownLatch提供了三个主要方法:

  • countDown():将计数器的值减1。
  • await():使当前线程等待,直到计数器的值为0。
  • await(long timeout, TimeUnit unit):使当前线程等待一段时间,直到计数器的值为0或者到达指定的超时时间。

CountDownLatch的使用示例

下面通过一个具体的示例来演示CountDownLatch的使用。

假设有一个订单处理系统,订单处理流程包括以下几个步骤:

  1. 从数据库中读取订单信息。
  2. 调用第三方接口进行支付操作。
  3. 将支付结果保存到数据库中。

其中,步骤2需要花费较长的时间。

首先,我们定义一个OrderProcessor类来处理订单。该类继承自Thread类,表示一个订单处理线程。

public class OrderProcessor extends Thread {
    private String orderId;
    private CountDownLatch latch;
    
    public OrderProcessor(String orderId, CountDownLatch latch) {
        this.orderId = orderId;
        this.latch = latch;
    }
    
    @Override
    public void run() {
        // 从数据库中读取订单信息
        Order order = getOrderFromDatabase(orderId);
        
        // 调用第三方接口进行支付操作
        boolean result = pay(order);
        
        // 将支付结果保存到数据库中
        savePaymentResult(orderId, result);
        
        // 计数器减1
        latch.countDown();
    }
    
    // 省略其他方法
}

run()方法中,我们首先从数据库中读取订单信息,然后调用第三方接口进行支付操作,最后将支付结果保存到数据库中。在执行完这些操作后,我们调用countDown()方法将计数器的值减1。

接下来,我们需要在主线程中等待所有订单处理线程执行完成后再进行后续操作。

public class MainThread {
    public static void main(String[] args) {
        // 从数据库中获取订单列表
        List<String> orderIds = getOrderIdsFromDatabase();
        
        // 创建计数器,初始值为订单数量
        CountDownLatch latch = new CountDownLatch(orderIds.size());
        
        // 创建订单处理线程并启动
        for (String orderId : orderIds) {
            OrderProcessor processor = new OrderProcessor(orderId, latch);
            processor.start();
        }
        
        try {
            // 等待所有订单处理线程执行完成
            latch.await();
            
            // 所有订单处理完成后,执行后续操作
            System.out.println("所有订单处理完成");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    // 省略其他方法
}

在主线程中,我们首先从数据库中获取订单列表,然后创建一个CountDownLatch对象,初始值设置为订单数量。接下来,我们创建订单处理线程并启动,每个订单处理线程都传入相同的计数器对象。最后,我们调用await()方法使主线程等待,直到所有订单处理线程执行完成。

当所有订单处理线程执行完成后,主线程继续执行后续操作。

类图

下面是OrderProcessor类和MainThread类的类图:

classDiagram
    class OrderProcessor {
        - String orderId
        - CountDownLatch latch