java线程池中何使用CountDownLatch和Future来实现等待所有线程执行完毕并获取返回值的

本文介绍如何在Java中利用Callable接口和ExecutorService.submit方法提交任务,通过CountDownLatch同步线程执行,最后获取每个任务的返回值并计算总和。
摘要由CSDN通过智能技术生成

如果你需要使用Callable接口来替代Runnable接口来执行任务,可以使用ExecutorService.submit(Callable)方法来提交任务,该方法会返回一个Future对象,该对象可以用来获取任务的返回值。

以下是一个示例代码,展示了如何使用CountDownLatch和Future来实现等待所有线程执行完毕并获取返回值的功能:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

public class WaitThreadExample {
    public static void main(String[] args) {
        int nThreads = 5;
        CountDownLatch latch = new CountDownLatch(nThreads);
        ExecutorService executor = Executors.newFixedThreadPool(nThreads);
        List<Future<Integer>> futures = new ArrayList<>();

        for (int i = 0; i < nThreads; i++) {
            futures.add(executor.submit(new Callable<Integer>() {
                public Integer call() throws Exception {
                    // 线程执行任务
                    System.out.println("Thread " + Thread.currentThread().getName() + " is running");
                    // 计数器减1
                    latch.countDown();
                    return 1; // 返回值
                }
            }));
        }

        // 等待所有线程执行完毕
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 输出结果
        int sum = 0;
        for (Future<Integer> future : futures) {
            try {
                sum += future.get(); // 获取返回值并累加
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        System.out.println("All threads have finished executing");
        System.out.println("Sum of return values: " + sum);

        // 关闭线程池
        executor.shutdown();
    }
}

上述代码与之前的示例代码类似,但是使用了Callable接口来执行任务,提交任务的方法也由executor.submit(Runnable)变为了executor.submit(Callable),同时List<Future> futures用来存储每个任务的Future对象,以便在所有任务执行完毕后获取它们的返回值。在每个Callable任务的call()方法中,除了执行任务之外,还使用latch.countDown()方法将计数器的值减1,并返回一个整数值1作为该任务的返回值。

在等待所有线程执行完毕之后,可以使用Future.get()方法获取每个任务的返回值,并将它们累加到sum变量中。最后输出计数器的值以及所有任务的返回值之和,并关闭线程池。

执行上述代码的结果应该是类似于以下的输出:

Thread pool-1-thread-2 is running
Thread pool-1-thread-1 is running
Thread pool-1-thread-3 is running
Thread pool-1-thread-4 is running
Thread pool-1-thread-5 is running
All threads have finished executing
Sum of return values: 5
如果你有两个线程池,并且想要使用 `CountDownLatch` 统计这两个线程池中的线程数量,可以创建两个 `CountDownLatch` 对象,并将计数器的值分别设置为对应线程池的大小。然后,在每个线程池中的任务执行完毕时,调用相应的 `CountDownLatch` 的 `countDown()` 方法来减少计数器的值。最后,通过调用 `await()` 方法等待两个 `CountDownLatch` 的计数器归零。以下是一个示例代码片段,展示了如何实现这一点: ```java int threadPoolSize1 = 5; // 第一个线程池的大小 int threadPoolSize2 = 3; // 第二个线程池的大小 // 创建两个 CountDownLatch,计数器的值分别设置为两个线程池线程的数量 CountDownLatch latch1 = new CountDownLatch(threadPoolSize1); CountDownLatch latch2 = new CountDownLatch(threadPoolSize2); // 创建第一个线程池 ExecutorService executorService1 = Executors.newFixedThreadPool(threadPoolSize1); // 提交任务到第一个线程池 for (int i = 0; i < threadPoolSize1; i++) { executorService1.submit(() -> { try { // 执行任务逻辑 } finally { // 任务执行完毕后,调用 countDown() 方法减少计数器的值 latch1.countDown(); } }); } // 创建第二个线程池 ExecutorService executorService2 = Executors.newFixedThreadPool(threadPoolSize2); // 提交任务到第二个线程池 for (int i = 0; i < threadPoolSize2; i++) { executorService2.submit(() -> { try { // 执行任务逻辑 } finally { // 任务执行完毕后,调用 countDown() 方法减少计数器的值 latch2.countDown(); } }); } try { // 使用 await() 方法等待两个 CountDownLatch 的计数器归零,即等待两个线程池中的所有线程执行完毕 latch1.await(); latch2.await(); // 在两个线程池中的所有线程执行完毕后,可以进行后续操作 } catch (InterruptedException e) { // 处理异常 } finally { // 关闭两个线程池 executorService1.shutdown(); executorService2.shutdown(); } ``` 在上述示例中,我们创建了两个 `CountDownLatch` 对象,并将计数器的值分别设置为两个线程池的大小。然后,我们分别创建了两个线程池,并提交了一定数量的任务到每个线程池中。在每个任务执行完毕后,我们调用相应的 `CountDownLatch` 的 `countDown()` 方法减少计数器的值。接下来,我们使用 `await()` 方法等待两个 `CountDownLatch` 的计数器归零,即等待两个线程池中的所有线程执行完毕。在所有线程执行完毕后,我们可以进行后续操作。最后,我们关闭两个线程池。 请注意,每个线程池的计数器值应该与相应线程池线程的数量保持一致,以确保所有线程执行完毕时计数器归零。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值