介绍下CompletableFuture的用法

CompletableFuture 用法详解

CompletableFuture 是 Java 8 引入的异步编程工具,实现了 FutureCompletionStage 接口,解决了传统 Future 只能阻塞获取结果、无法链式调用的问题,支持异步执行、链式处理、多任务组合等能力,是 Java 异步编程的核心工具之一。

一、核心优势

  1. 非阻塞获取结果:支持回调函数,无需阻塞等待任务完成。
  2. 链式调用:多个异步任务可以按顺序链式执行,代码更简洁。
  3. 多任务组合:支持多个异步任务的并行执行、依赖执行、任意一个完成/全部完成等组合场景。
  4. 异常处理:提供专门的异常处理方法,避免异常丢失。

二、基本使用:创建异步任务

CompletableFuture 提供了多种静态方法来创建异步任务,主要分为无返回值有返回值 两类,底层可指定线程池(默认使用 ForkJoinPool.commonPool())。

1. 无返回值的异步任务

  • runAsync(Runnable runnable):使用默认线程池执行 Runnable 任务。
  • runAsync(Runnable runnable, Executor executor):使用指定线程池执行 Runnable 任务。
java 复制代码
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;

public class CompletableFutureDemo {
    public static void main(String[] args) throws InterruptedException {
        // 使用默认线程池执行无返回值任务
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("任务1执行完成(无返回值)");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 使用自定义线程池执行无返回值任务
        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("任务2执行完成(无返回值)");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, Executors.newFixedThreadPool(2));

        // 阻塞等待所有任务完成(仅演示,实际不推荐阻塞)
        Thread.sleep(2000);
    }
}

2. 有返回值的异步任务

  • supplyAsync(Supplier<U> supplier):使用默认线程池执行 Supplier 任务,返回结果。
  • supplyAsync(Supplier<U> supplier, Executor executor):使用指定线程池执行 Supplier 任务,返回结果。
java 复制代码
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;

public class CompletableFutureDemo {
    public static void main(String[] args) throws Exception {
        // 使用默认线程池执行有返回值任务
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
                return "任务1返回结果";
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });

        // 使用自定义线程池执行有返回值任务
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
                return 100;
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, Executors.newFixedThreadPool(2));

        // 获取结果(阻塞式,仅演示,推荐使用回调函数)
        System.out.println(future1.get()); // 输出:任务1返回结果
        System.out.println(future2.get()); // 输出:100
    }
}

三、链式调用:处理任务结果

CompletableFuture 提供了一系列方法来处理异步任务的结果,实现链式调用,核心方法分为同步处理异步处理 (方法名带 Async)。

1. thenApply / thenApplyAsync

接收上一个任务的结果,处理后返回新的结果(映射)。

  • thenApply:在当前线程(或上一个任务的线程)执行。
  • thenApplyAsync:使用默认/指定线程池执行。
java 复制代码
import java.util.concurrent.CompletableFuture;

public class CompletableFutureDemo {
    public static void main(String[] args) throws Exception {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            return 10; // 第一步:返回10
        }).thenApply(num -> {
            return num * 2; // 第二步:乘以2,返回20
        }).thenApply(num -> {
            return num + 5; // 第三步:加5,返回25
        });

        System.out.println(future.get()); // 输出:25
    }
}

2. thenAccept / thenAcceptAsync

接收上一个任务的结果,消费结果(无返回值,消费)。

java 复制代码
import java.util.concurrent.CompletableFuture;

public class CompletableFutureDemo {
    public static void main(String[] args) throws Exception {
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }).thenAccept(str -> {
            System.out.println(str + " World"); // 输出:Hello World
        });

        future.get();
    }
}

3. thenRun / thenRunAsync

不接收上一个任务的结果,仅执行后续操作(无参数、无返回值)。

java 复制代码
import java.util.concurrent.CompletableFuture;

public class CompletableFutureDemo {
    public static void main(String[] args) throws Exception {
        CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
            return 100;
        }).thenRun(() -> {
            System.out.println("任务执行完成,执行后续操作"); // 输出:任务执行完成,执行后续操作
        });

        future.get();
    }
}

4. thenCompose / thenComposeAsync

处理嵌套的 CompletableFuture (扁平化),与 thenApply 的区别:thenApply 返回普通值,thenCompose 返回 CompletableFuture。

java 复制代码
import java.util.concurrent.CompletableFuture;

public class CompletableFutureDemo {
    // 模拟根据数字获取字符串的异步方法
    private static CompletableFuture<String> getStringAsync(int num) {
        return CompletableFuture.supplyAsync(() -> "数字:" + num);
    }

    public static void main(String[] args) throws Exception {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> 10)
                .thenCompose(num -> getStringAsync(num)); // 扁平化嵌套的CompletableFuture

        System.out.println(future.get()); // 输出:数字:10
    }
}

5. thenCombine / thenCombineAsync

组合两个独立的 CompletableFuture 结果,处理后返回新结果。

java 复制代码
import java.util.concurrent.CompletableFuture;

public class CompletableFutureDemo {
    public static void main(String[] args) throws Exception {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
        CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);

        // 组合两个结果,求和
        CompletableFuture<Integer> resultFuture = future1.thenCombine(future2, (num1, num2) -> num1 + num2);

        System.out.println(resultFuture.get()); // 输出:30
    }
}

四、多任务组合

CompletableFuture 支持多个异步任务的组合执行,满足并行处理场景。

1. allOf:等待所有任务完成

无返回值,仅等待所有传入的 CompletableFuture 完成(无论成功/失败)。

java 复制代码
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(1000);
                System.out.println("任务1完成");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(2000);
                System.out.println("任务2完成");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 等待所有任务完成
        CompletableFuture<Void> allFuture = CompletableFuture.allOf(future1, future2);
        allFuture.get(); // 阻塞直到所有任务完成

        System.out.println("所有任务都完成了");
    }
}

2. anyOf:等待任意一个任务完成

返回第一个完成的任务的结果(无论成功/失败)。

java 复制代码
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(2000);
                return "任务1结果";
            } catch (InterruptedException e) {
                return "任务1异常";
            }
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
                return "任务2结果";
            } catch (InterruptedException e) {
                return "任务2异常";
            }
        });

        // 等待任意一个任务完成
        CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2);
        System.out.println(anyFuture.get()); // 输出:任务2结果(因为任务2先完成)
    }
}

五、异常处理

CompletableFuture 提供了专门的异常处理方法,避免异常丢失。

1. exceptionally

捕获上一个任务的异常,返回默认值(类似 try-catch 的 catch 块)。

java 复制代码
import java.util.concurrent.CompletableFuture;

public class CompletableFutureDemo {
    public static void main(String[] args) throws Exception {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            // 模拟异常
            int num = 1 / 0;
            return num;
        }).exceptionally(e -> {
            // 捕获异常,返回默认值0
            System.out.println("异常信息:" + e.getMessage());
            return 0;
        });

        System.out.println(future.get()); // 输出:0
    }
}

2. handle / handleAsync

无论上一个任务成功还是失败,都执行处理逻辑(类似 try-catch-finally 的 finally 块,支持处理结果和异常)。

java 复制代码
import java.util.concurrent.CompletableFuture;

public class CompletableFutureDemo {
    public static void main(String[] args) throws Exception {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            // 模拟异常(注释掉则返回10)
            // int num = 1 / 0;
            return 10;
        }).handle((result, e) -> {
            if (e != null) {
                System.out.println("异常信息:" + e.getMessage());
                return -1;
            } else {
                return result * 2;
            }
        });

        System.out.println(future.get()); // 无异常输出20,有异常输出-1
    }
}

3. whenComplete / whenCompleteAsync

无论成功还是失败,都执行回调(不改变结果,仅做通知/日志)。

java 复制代码
import java.util.concurrent.CompletableFuture;

public class CompletableFutureDemo {
    public static void main(String[] args) throws Exception {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            // 模拟异常
            // int num = 1 / 0;
            return 10;
        }).whenComplete((result, e) -> {
            if (e != null) {
                System.out.println("任务失败:" + e.getMessage());
            } else {
                System.out.println("任务成功:" + result);
            }
        });

        System.out.println(future.get()); // 无异常输出10,有异常抛出异常
    }
}

六、注意事项

  1. 线程池选择 :默认使用 ForkJoinPool.commonPool(),核心线程数为 CPU 核心数 - 1,若任务是 IO 密集型,建议使用自定义线程池(如 ThreadPoolExecutor),避免线程池耗尽。
  2. 异常处理 :异步任务的异常不会主动抛出,必须通过 exceptionallyhandle 等方法处理,否则会导致异常丢失。
  3. 避免阻塞get()join() 是阻塞方法,尽量使用回调函数(如 thenAccept)替代,否则失去异步优势。
  4. 内存泄漏:若 CompletableFuture 未完成且被长期持有,可能导致线程和资源泄漏,需确保任务能正常完成或超时。

总结

CompletableFuture 是 Java 异步编程的核心工具,通过创建异步任务、链式处理结果、多任务组合、异常处理 等能力,解决了传统 Future 的局限性。在实际开发中,常用于处理 IO 密集型任务(如网络请求、数据库操作)、并行计算等场景,能有效提升程序的并发性能和响应速度。

相关推荐
༾冬瓜大侠༿2 小时前
C++内存和模板
java·开发语言·c++
半路_出家ren2 小时前
Python操作MySQL(详细版)
运维·开发语言·数据库·python·mysql·网络安全·wireshark
共享家95272 小时前
MYSQL-内外连接
开发语言·数据库·mysql
吴佳浩 Alben2 小时前
Python入门指南(七) - YOLO检测API进阶实战
开发语言·python·yolo
BestAns10 小时前
一文带你吃透 Java 反射机制
java·后端
沐知全栈开发10 小时前
HTML5 浏览器支持
开发语言
wasp52010 小时前
AgentScope Java 核心架构深度解析
java·开发语言·人工智能·架构·agentscope
WHOVENLY10 小时前
【javaScript】- 笔试题合集(长期更新,建议收藏,目前已更新至31题)
开发语言·前端·javascript
2501_9167665410 小时前
【Springboot】数据层开发-数据源自动管理
java·spring boot·后端