教程中心 / Java教程 / Future和异步

Future和异步编程

20分钟 多线程

引言:什么是异步编程?

异步编程是一种编程范式,允许程序在等待某些耗时操作(如网络请求、文件读取、数据库查询)完成时,继续执行其他任务,从而提高程序的效率和响应性。

同步 vs 异步类比

同步模式:像点餐后一直在餐厅等菜
- 你点了宫保鸡丁
- 服务员说需要20分钟
- 你就一直坐在那里等
- 等了20分钟后,终于吃到

异步模式:像点外卖
- 你点了宫保鸡丁
- 外卖小哥说需要20分钟
- 你可以做其他事情(工作、看电视)
- 20分钟后外卖到了,你去取

Future/CompletableFuture就是你的"外卖订单":可以用来检查状态和获取结果

Future接口

Future是Java 5引入的接口,表示一个异步计算的结果。你可以提交一个任务给线程池,然后通过Future来检查任务是否完成、获取结果等。

Future接口核心方法

方法说明
get()阻塞等待并获取结果
get(timeout)阻塞等待,带超时
isDone()判断是否完成
isCancelled()判断是否被取消
cancel(boolean)尝试取消任务

Future基本用法

import java.util.concurrent.*;

ExecutorService executor = Executors.newFixedThreadPool(2);

// 提交异步任务,返回Future
Future future = executor.submit(() -> {
    Thread.sleep(1000);  // 模拟耗时操作
    return 42 * 2;
});

// 执行其他任务
System.out.println("做其他事情...");

// 通过Future获取结果(会阻塞直到结果可用)
Integer result = future.get();
System.out.println("计算结果: " + result);

executor.shutdown();

Future的局限性

Future的不足:

  • 不能手动完成:无法手动设置Future的结果
  • 不能链式调用:无法方便地组合多个Future
  • 没有异常处理:无法直接处理异步任务的异常
  • 轮询判断完成:需要不断调用isDone()来检查状态

CompletableFuture详解

CompletableFuture是Java 8引入的增强版Future,完美解决了Future的局限性,支持函数式编程、链式调用、组合操作和强大的异常处理。

创建CompletableFuture

import java.util.concurrent.CompletableFuture;

// 方式1:使用supplyAsync(有返回值)
CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
    return "Hello";
});

// 方式2:使用runAsync(无返回值)
CompletableFuture cf2 = CompletableFuture.runAsync(() -> {
    System.out.println("执行异步任务");
});

// 方式3:手动完成
CompletableFuture cf3 = new CompletableFuture<>();
cf3.complete("手动设置结果");

CompletableFuture常用方法分类

类别方法说明
创建supplyAsync(Runnable)异步执行,有返回值
runAsync(Runnable)异步执行,无返回值
转换thenApply(Function)转换结果
thenApplyAsync()异步转换
消费thenAccept(Consumer)消费结果
thenRun(Runnable)不关心结果,只执行操作
组合thenCompose(Function)扁平化Future
thenCombine(Completion)组合两个Future
异常exceptionally(Function)处理异常
handle(BiFunction)无论成功失败都处理

链式调用详解

thenApply - 转换结果

// thenApply:接收上一个结果,进行转换
CompletableFuture cf = CompletableFuture
    .supplyAsync(() -> "Hello")
    .thenApply(s -> s.length());  // "Hello" -> 5

System.out.println(cf.join());  // 输出 5

// 连续转换
CompletableFuture cf2 = CompletableFuture
    .supplyAsync(() -> "Hello World")
    .thenApply(s -> s.toUpperCase())   // "HELLO WORLD"
    .thenApply(s -> s.length());       // 11

System.out.println(cf2.join());  // 11

thenAccept - 消费结果

// thenAccept:只消费结果,不返回新值
CompletableFuture
    .supplyAsync(() -> "Hello")
    .thenAccept(s -> System.out.println("收到: " + s));

// thenRun:不关心上一步结果,只执行操作
CompletableFuture
    .supplyAsync(() -> 100)
    .thenRun(() -> System.out.println("任务完成"));  // 只打印,不使用结果

thenCompose - 扁平化Future(链式异步)

// thenCompose:用于返回CompletableFuture的方法,避免嵌套
// 场景:根据用户ID获取用户,再获取用户的订单

// 错误写法(使用thenApply会导致嵌套)
CompletableFuture userFuture = getUserById(1);
CompletableFuture> orderNested = userFuture
    .thenApply(user -> getOrderByUserId(user.getId()));

// 正确写法(使用thenCompose扁平化)
CompletableFuture orderFuture = userFuture
    .thenCompose(user -> getOrderByUserId(user.getId()));

// 实际示例
CompletableFuture cf = CompletableFuture
    .supplyAsync(() -> "Hello")
    .thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World"));

System.out.println(cf.join());  // "Hello World"

thenCombine - 组合两个Future

// thenCombine:组合两个独立的CompletableFuture
CompletableFuture cf1 = CompletableFuture
    .supplyAsync(() -> "Hello");
CompletableFuture cf2 = CompletableFuture
    .supplyAsync(() -> "World");

// 等待两个都完成后,合并结果
CompletableFuture combined = cf1
    .thenCombine(cf2, (s1, s2) -> s1 + " " + s2);

System.out.println(combined.join());  // "Hello World"

// 更多示例:计算价格
CompletableFuture basePrice = CompletableFuture
    .supplyAsync(() -> 100.0);
CompletableFuture tax = CompletableFuture
    .supplyAsync(() -> 10.0);

CompletableFuture total = basePrice
    .thenCombine(tax, (price, t) -> price + t);

System.out.println("总价: " + total.join());  // 110.0

异常处理

exceptionally - 捕获异常

// exceptionally:处理异常,返回默认值
CompletableFuture cf = CompletableFuture
    .supplyAsync(() -> {
        if (true) throw new RuntimeException("出错了!");
        return 100;
    })
    .exceptionally(ex -> {
        System.out.println("捕获异常: " + ex.getMessage());
        return -1;  // 返回默认值
    });

System.out.println("结果: " + cf.join());  // -1

handle - 无论成功失败都处理

// handle:无论成功还是失败都会执行
CompletableFuture cf = CompletableFuture
    .supplyAsync(() -> {
        if (true) throw new RuntimeException("失败");
        return 100;
    })
    .handle((result, ex) -> {
        if (ex != null) {
            System.out.println("发生异常: " + ex.getMessage());
            return 0;  // 异常时返回0
        }
        return result;  // 成功时返回原结果
    });

System.out.println("最终结果: " + cf.join());  // 0

whenComplete - 完成时回调

// whenComplete:完成时的回调(不修改结果)
CompletableFuture cf = CompletableFuture
    .supplyAsync(() -> "Hello")
    .thenApply(s -> s.toUpperCase())
    .whenComplete((result, ex) -> {
        if (ex != null) {
            System.out.println("异常: " + ex);
        } else {
            System.out.println("完成,结果: " + result);
        }
    });

cf.join();  // 输出:完成,结果:HELLO

实战应用场景

场景1:异步获取用户信息

// 模拟异步服务
CompletableFuture getUserById(Long id) {
    return CompletableFuture.supplyAsync(() -> {
        // 模拟数据库查询
        return new User(id, "User" + id);
    });
}

CompletableFuture getOrderByUserId(Long userId) {
    return CompletableFuture.supplyAsync(() -> {
        // 模拟查询订单
        return new Order(userId, "Order-001");
    });
}

// 链式调用获取用户和订单
getUserById(1L)
    .thenCompose(user -> getOrderByUserId(user.getId()))
    .thenAccept(order -> System.out.println("订单: " + order))
    .exceptionally(ex -> {
        System.out.println("错误: " + ex.getMessage());
        return null;
    })
    .join();

场景2:并行获取多个数据源

// 并行获取用户信息、订单、推荐商品
CompletableFuture userFuture = getUserById(1L);
CompletableFuture> ordersFuture = getOrders(1L);
CompletableFuture> recommendFuture = getRecommendations(1L);

// 等待所有完成
CompletableFuture.allOf(userFuture, ordersFuture, recommendFuture)
    .thenRun(() -> {
        User user = userFuture.join();
        List orders = ordersFuture.join();
        List products = recommendFuture.join();
        System.out.println("用户: " + user);
        System.out.println("订单数: " + orders.size());
        System.out.println("推荐商品数: " + products.size());
    })
    .join();

场景3:异步HTTP请求

// 模拟异步HTTP调用
CompletableFuture fetchUserData() {
    return CompletableFuture.supplyAsync(() -> {
        // 模拟HTTP请求
        return "UserData";
    });
}

CompletableFuture fetchProductData() {
    return CompletableFuture.supplyAsync(() -> {
        return "ProductData";
    });
}

// 并行获取后合并
CompletableFuture combinedData = fetchUserData()
    .thenCombine(fetchProductData(), (user, product) -> {
        return user + " + " + product;
    });

System.out.println(combinedData.join());

使用线程池

// 默认使用ForkJoinPool.commonPool()(公共线程池)
CompletableFuture cf1 = CompletableFuture
    .supplyAsync(() -> "Hello");

// 也可以指定线程池
ExecutorService executor = Executors.newFixedThreadPool(4);
CompletableFuture cf2 = CompletableFuture
    .supplyAsync(() -> "World", executor);

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

常用场景总结

thenApply:同步转换结果
thenApplyAsync:异步转换结果
thenAccept:消费结果
thenCompose:链式Future(返回CompletableFuture)
thenCombine:并行Future合并
exceptionally:异常处理

小结

  • Future表示异步计算结果,但功能有限
  • CompletableFuture是增强版Future,支持函数式编程
  • supplyAsync:创建有返回值的异步任务
  • runAsync:创建无返回值的异步任务
  • thenApply:转换结果
  • thenCompose:扁平化Future,链接多个异步操作
  • thenCombine:并行执行多个异步操作并合并结果
  • exceptionally/handle:异常处理
☕ Java 在线代码编辑器
📝 运行结果