导读:本期聚焦于小伙伴创作的《如何正确等待 CompletableFuture 异步任务全部完成》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何正确等待 CompletableFuture 异步任务全部完成》有用,将其分享出去将是对创作者最好的鼓励。

在Java异步编程场景中,我们经常会提交多个CompletableFuture异步任务并行执行,之后需要等待所有任务全部完成再汇总结果或者执行后续逻辑。不同的等待方式在异常处理、阻塞特性、返回值等方面存在差异,需要根据实际需求选择合适的方法。

如何正确等待 CompletableFuture 异步任务全部完成

使用allOf方法结合join等待

CompletableFuture的静态方法allOf可以接收多个CompletableFuture实例,返回一个全新的CompletableFuture<Void>对象,当所有传入的异步任务都完成时,这个新的CompletableFuture才会完成。如果我们需要等待所有任务完成,并且不关心每个任务的单独返回值,可以使用这种方式。

示例代码如下:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletableFutureWaitDemo {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        // 创建三个异步任务
        CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "任务1完成";
        }, executor);

        CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "任务2完成";
        }, executor);

        CompletableFuture<String> task3 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(800);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "任务3完成";
        }, executor);

        // 等待所有任务完成,不关心单个结果
        CompletableFuture<Void> allTasks = CompletableFuture.allOf(task1, task2, task3);
        allTasks.join(); // 阻塞等待所有任务完成
        System.out.println("所有异步任务都已完成");

        // 如果需要获取每个任务的结果,可以单独调用join
        try {
            String result1 = task1.get();
            String result2 = task2.get();
            String result3 = task3.get();
            System.out.println("任务1结果:" + result1);
            System.out.println("任务2结果:" + result2);
            System.out.println("任务3结果:" + result3);
        } catch (Exception e) {
            e.printStackTrace();
        }

        executor.shutdown();
    }
}

这种方式中,join方法会阻塞当前线程直到对应的CompletableFuture完成,和get方法的区别是join不会抛出受检异常,不需要强制捕获,使用起来更简洁。

使用allOf方法结合get等待

如果我们希望捕获等待过程中的异常,或者需要遵循方法签名抛出异常的要求,可以使用get方法来等待allOf返回的任务完成。get方法会抛出InterruptedException和ExecutionException,需要我们进行异常处理。

示例代码如下:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletableFutureGetDemo {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        CompletableFuture<Integer> taskA = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 100;
        }, executor);

        CompletableFuture<Integer> taskB = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(700);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return 200;
        }, executor);

        CompletableFuture<Void> allTask = CompletableFuture.allOf(taskA, taskB);
        try {
            allTask.get(); // 阻塞等待,会抛出受检异常
            System.out.println("所有任务完成,任务A结果:" + taskA.get() + ",任务B结果:" + taskB.get());
        } catch (Exception e) {
            System.out.println("等待任务过程中出现异常:" + e.getMessage());
        }

        executor.shutdown();
    }
}

等待过程中异常处理注意事项

当使用allOf等待多个任务时,如果其中任意一个任务出现异常,那么allOf返回的CompletableFuture也会异常完成,此时调用join或者get都会抛出异常。如果需要处理单个任务的异常,避免单个任务失败影响整体等待,需要提前给每个异步任务添加异常处理逻辑。

示例代码如下:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletableFutureExceptionDemo {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        // 任务3会抛出异常
        CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> "任务1正常完成", executor);
        CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> "任务2正常完成", executor);
        CompletableFuture<String> task3 = CompletableFuture.supplyAsync(() -> {
            throw new RuntimeException("任务3执行失败");
        }, executor).exceptionally(ex -> {
            // 处理任务3的异常,返回默认值,避免任务3异常导致整体等待失败
            System.out.println("任务3出现异常,已处理:" + ex.getMessage());
            return "任务3默认结果";
        });

        CompletableFuture<Void> allTasks = CompletableFuture.allOf(task1, task2, task3);
        allTasks.join();
        System.out.println("所有任务处理完成");
        System.out.println("任务1结果:" + task1.join());
        System.out.println("任务2结果:" + task2.join());
        System.out.println("任务3结果:" + task3.join());

        executor.shutdown();
    }
}

不同等待方式对比

以下是几种常见等待方式的对比:

等待方式阻塞特性异常处理适用场景
allOf + join阻塞当前线程不抛出受检异常,运行时异常直接抛出不需要捕获受检异常,代码简洁的场景
allOf + get阻塞当前线程抛出InterruptedException和ExecutionException,需要显式处理需要捕获等待过程异常,或者方法签名要求抛出受检异常的场景
allOf + thenRun回调不阻塞当前线程,任务完成后触发回调回调中处理异常,或者提前给每个任务加异常处理非阻塞等待,等待完成后执行后续逻辑的场景

非阻塞等待方式

如果我们不希望阻塞当前线程,可以在allOf返回的任务上添加回调,当所有任务完成时自动执行后续逻辑,不需要主动调用join或者get进行阻塞等待。

示例代码如下:

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CompletableFutureCallbackDemo {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "回调任务1完成";
        }, executor);

        CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(400);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "回调任务2完成";
        }, executor);

        CompletableFuture<Void> allTasks = CompletableFuture.allOf(task1, task2);
        // 添加回调,所有任务完成后执行,不阻塞当前线程
        allTasks.thenRun(() -> {
            System.out.println("所有任务完成,执行回调逻辑");
            System.out.println("任务1结果:" + task1.join());
            System.out.println("任务2结果:" + task2.join());
        });

        System.out.println("主线程继续执行其他逻辑");
        executor.shutdown();
    }
}

这种非阻塞方式适合异步任务等待后不需要立即获取结果,而是执行一些后续操作的场景,不会阻塞主线程的执行。

CompletableFuture异步任务allOfjoinget修改时间:2026-06-13 12:54:45

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。