CompletableFuture异步编程实战

JDK8 CompletableFuture异步编程实战

目录


一、CompletableFuture概述

1.1 为什么需要CompletableFuture

在JDK 8之前,Java异步编程主要依赖FutureCallable,但存在诸多不足:

diff 复制代码
Future的局限性:
+---------------------------+
| ✗ 无法手动完成             |
| ✗ 无法链式调用             |
| ✗ 无法组合多个Future       |
| ✗ 无法处理异常             |
| ✗ 阻塞式获取结果           |
+---------------------------+

CompletableFuture的优势:
+---------------------------+
| ✓ 支持手动完成             |
| ✓ 支持链式调用             |
| ✓ 多个Future组合          |
| ✓ 完善的异常处理           |
| ✓ 非阻塞式编程             |
+---------------------------+
java 复制代码
package com.example.completablefuture;

import java.util.concurrent.*;

/**
 * Future vs CompletableFuture对比
 */
public class FutureVsCompletableFuture {

    public static void main(String[] args) throws Exception {

        // === 1. 传统Future的问题 ===
        System.out.println("=== 传统Future ===");

        ExecutorService executor = Executors.newFixedThreadPool(2);

        // 提交任务
        Future<String> future = executor.submit(() -> {
            Thread.sleep(1000);
            return "Hello Future";
        });

        // 只能阻塞等待结果
        System.out.println("阻塞等待结果...");
        String result = future.get(); // 阻塞
        System.out.println("结果: " + result);

        // === 2. CompletableFuture的优势 ===
        System.out.println("\n=== CompletableFuture ===");

        // 异步执行
        CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "Hello CompletableFuture";
        });

        // 非阻塞式处理结果
        cf.thenAccept(res -> System.out.println("结果: " + res));

        // 链式调用
        CompletableFuture<String> chain = CompletableFuture
            .supplyAsync(() -> "Step 1")
            .thenApply(s -> s + " -> Step 2")
            .thenApply(s -> s + " -> Step 3");

        System.out.println("链式调用结果: " + chain.get());

        executor.shutdown();

        // 等待异步任务完成
        Thread.sleep(2000);
    }
}

1.2 CompletableFuture核心方法分类

diff 复制代码
方法分类:
+------------------+------------------------+--------------------+
|    类型          |       方法             |      说明          |
+------------------+------------------------+--------------------+
| 创建             | supplyAsync            | 有返回值           |
|                  | runAsync               | 无返回值           |
+------------------+------------------------+--------------------+
| 转换             | thenApply              | 同步转换           |
|                  | thenApplyAsync         | 异步转换           |
+------------------+------------------------+--------------------+
| 消费             | thenAccept             | 消费结果           |
|                  | thenRun                | 不接收结果         |
+------------------+------------------------+--------------------+
| 组合             | thenCompose            | 串行组合           |
|                  | thenCombine            | 并行组合           |
|                  | allOf                  | 等待所有完成       |
|                  | anyOf                  | 等待任一完成       |
+------------------+------------------------+--------------------+
| 异常处理         | exceptionally          | 异常处理           |
|                  | handle                 | 正常+异常处理      |
|                  | whenComplete           | 完成时回调         |
+------------------+------------------------+--------------------+

二、创建CompletableFuture

2.1 基本创建方式

java 复制代码
package com.example.completablefuture;

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

/**
 * CompletableFuture创建方式
 */
public class CreateCompletableFuture {

    public static void main(String[] args) throws Exception {

        // === 1. supplyAsync - 有返回值的异步任务 ===
        System.out.println("=== supplyAsync ===");

        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("执行异步任务: " + Thread.currentThread().getName());
            return "Hello";
        });

        System.out.println("结果: " + future1.get());

        // === 2. runAsync - 无返回值的异步任务 ===
        System.out.println("\n=== runAsync ===");

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            System.out.println("执行无返回值任务: " + Thread.currentThread().getName());
        });

        future2.get(); // 等待完成

        // === 3. 使用自定义线程池 ===
        System.out.println("\n=== 自定义线程池 ===");

        ExecutorService executor = Executors.newFixedThreadPool(5);

        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
            System.out.println("自定义线程池: " + Thread.currentThread().getName());
            return "Custom Thread Pool";
        }, executor);

        System.out.println("结果: " + future3.get());

        // === 4. completedFuture - 已完成的Future ===
        System.out.println("\n=== completedFuture ===");

        CompletableFuture<String> completed = CompletableFuture.completedFuture("立即完成");
        System.out.println("结果: " + completed.get());

        // === 5. 手动完成 ===
        System.out.println("\n=== 手动完成 ===");

        CompletableFuture<String> manual = new CompletableFuture<>();

        // 在另一个线程中完成
        new Thread(() -> {
            try {
                Thread.sleep(1000);
                manual.complete("手动完成的结果");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        System.out.println("等待手动完成...");
        System.out.println("结果: " + manual.get());

        executor.shutdown();
    }
}

三、结果处理与转换

3.1 thenApply、thenAccept、thenRun

java 复制代码
package com.example.completablefuture;

import java.util.concurrent.CompletableFuture;

/**
 * 结果处理与转换
 */
public class ResultProcessing {

    public static void main(String[] args) throws Exception {

        // === 1. thenApply - 转换结果(有返回值) ===
        System.out.println("=== thenApply ===");

        CompletableFuture<Integer> future1 = CompletableFuture
            .supplyAsync(() -> {
                System.out.println("步骤1: 返回10");
                return 10;
            })
            .thenApply(num -> {
                System.out.println("步骤2: " + num + " * 2");
                return num * 2;
            })
            .thenApply(num -> {
                System.out.println("步骤3: " + num + " + 5");
                return num + 5;
            });

        System.out.println("最终结果: " + future1.get()); // 25

        // === 2. thenAccept - 消费结果(无返回值) ===
        System.out.println("\n=== thenAccept ===");

        CompletableFuture<Void> future2 = CompletableFuture
            .supplyAsync(() -> "Hello World")
            .thenAccept(str -> {
                System.out.println("消费结果: " + str);
            });

        future2.get();

        // === 3. thenRun - 不关心结果(无返回值) ===
        System.out.println("\n=== thenRun ===");

        CompletableFuture<Void> future3 = CompletableFuture
            .supplyAsync(() -> "Some Result")
            .thenRun(() -> {
                System.out.println("任务完成,执行后续操作");
            });

        future3.get();

        // === 4. 同步 vs 异步 ===
        System.out.println("\n=== 同步 vs 异步 ===");

        // thenApply: 同步执行(使用相同线程)
        CompletableFuture.supplyAsync(() -> {
            System.out.println("supplyAsync: " + Thread.currentThread().getName());
            return "Result";
        }).thenApply(s -> {
            System.out.println("thenApply: " + Thread.currentThread().getName());
            return s.toUpperCase();
        }).get();

        // thenApplyAsync: 异步执行(使用不同线程)
        CompletableFuture.supplyAsync(() -> {
            System.out.println("supplyAsync: " + Thread.currentThread().getName());
            return "Result";
        }).thenApplyAsync(s -> {
            System.out.println("thenApplyAsync: " + Thread.currentThread().getName());
            return s.toUpperCase();
        }).get();

        // === 5. 链式调用示例 ===
        demonstrateChaining();
    }

    /**
     * 链式调用示例
     */
    private static void demonstrateChaining() throws Exception {
        System.out.println("\n=== 链式调用示例 ===");

        String result = CompletableFuture
            .supplyAsync(() -> "hello")
            .thenApply(String::toUpperCase)
            .thenApply(s -> s + " WORLD")
            .thenApply(s -> s + "!")
            .get();

        System.out.println("链式调用结果: " + result);
    }
}

四、多任务组合

4.1 thenCompose与thenCombine

java 复制代码
package com.example.completablefuture;

import java.util.concurrent.CompletableFuture;

/**
 * 多任务组合
 */
public class TaskCombination {

    public static void main(String[] args) throws Exception {

        // === 1. thenCompose - 串行组合(依赖) ===
        System.out.println("=== thenCompose (串行) ===");

        CompletableFuture<String> compose = CompletableFuture
            .supplyAsync(() -> {
                System.out.println("任务1: 查询用户ID");
                return "USER_001";
            })
            .thenCompose(userId -> CompletableFuture.supplyAsync(() -> {
                System.out.println("任务2: 根据" + userId + "查询用户详情");
                return "User{name='张三', id='" + userId + "'}";
            }));

        System.out.println("结果: " + compose.get());

        // === 2. thenCombine - 并行组合(独立) ===
        System.out.println("\n=== thenCombine (并行) ===");

        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            sleep(1000);
            System.out.println("任务1: 查询用户信息");
            return "User: 张三";
        });

        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            sleep(1000);
            System.out.println("任务2: 查询订单信息");
            return "Order: ORD001";
        });

        CompletableFuture<String> combined = future1.thenCombine(future2, (user, order) -> {
            System.out.println("合并结果");
            return user + " | " + order;
        });

        System.out.println("组合结果: " + combined.get());

        // === 3. allOf - 等待所有任务完成 ===
        System.out.println("\n=== allOf ===");

        CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> {
            sleep(1000);
            return "任务1完成";
        });

        CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> {
            sleep(2000);
            return "任务2完成";
        });

        CompletableFuture<String> task3 = CompletableFuture.supplyAsync(() -> {
            sleep(1500);
            return "任务3完成";
        });

        long start = System.currentTimeMillis();

        CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(task1, task2, task3);

        allOfFuture.get(); // 等待所有完成

        long end = System.currentTimeMillis();

        System.out.println("所有任务完成,耗时: " + (end - start) + "ms");
        System.out.println("结果1: " + task1.get());
        System.out.println("结果2: " + task2.get());
        System.out.println("结果3: " + task3.get());

        // === 4. anyOf - 等待任一任务完成 ===
        System.out.println("\n=== anyOf ===");

        CompletableFuture<String> slow = CompletableFuture.supplyAsync(() -> {
            sleep(3000);
            return "慢任务";
        });

        CompletableFuture<String> fast = CompletableFuture.supplyAsync(() -> {
            sleep(1000);
            return "快任务";
        });

        CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(slow, fast);

        System.out.println("最快完成的任务: " + anyOfFuture.get());
    }

    private static void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

4.2 复杂组合示例

java 复制代码
package com.example.completablefuture;

import java.util.concurrent.CompletableFuture;

/**
 * 复杂任务组合示例
 */
public class ComplexCombination {

    public static void main(String[] args) throws Exception {

        // 场景: 电商商品详情页数据聚合
        // 需要并行获取: 商品基本信息、库存信息、评价信息、推荐商品

        System.out.println("=== 商品详情页数据聚合 ===\n");

        long start = System.currentTimeMillis();

        // 1. 查询商品基本信息
        CompletableFuture<String> productInfo = CompletableFuture.supplyAsync(() -> {
            sleep(500);
            System.out.println("✓ 获取商品基本信息");
            return "iPhone 15 Pro";
        });

        // 2. 查询库存信息
        CompletableFuture<Integer> stockInfo = CompletableFuture.supplyAsync(() -> {
            sleep(300);
            System.out.println("✓ 获取库存信息");
            return 100;
        });

        // 3. 查询评价信息
        CompletableFuture<String> reviewInfo = CompletableFuture.supplyAsync(() -> {
            sleep(600);
            System.out.println("✓ 获取评价信息");
            return "4.8分(1000评价)";
        });

        // 4. 查询推荐商品
        CompletableFuture<String> recommendInfo = CompletableFuture.supplyAsync(() -> {
            sleep(400);
            System.out.println("✓ 获取推荐商品");
            return "推荐: AirPods Pro";
        });

        // 组合所有结果
        CompletableFuture<ProductDetail> result = productInfo
            .thenCombine(stockInfo, (product, stock) -> {
                ProductDetail detail = new ProductDetail();
                detail.setProductName(product);
                detail.setStock(stock);
                return detail;
            })
            .thenCombine(reviewInfo, (detail, review) -> {
                detail.setReview(review);
                return detail;
            })
            .thenCombine(recommendInfo, (detail, recommend) -> {
                detail.setRecommend(recommend);
                return detail;
            });

        ProductDetail detail = result.get();

        long end = System.currentTimeMillis();

        System.out.println("\n=== 商品详情 ===");
        System.out.println(detail);
        System.out.println("\n总耗时: " + (end - start) + "ms (并行执行)");
        System.out.println("如果串行执行需要: ~1800ms");
    }

    private static void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

/**
 * 商品详情VO
 */
class ProductDetail {
    private String productName;
    private Integer stock;
    private String review;
    private String recommend;

    // Getters and Setters
    public void setProductName(String productName) { this.productName = productName; }
    public void setStock(Integer stock) { this.stock = stock; }
    public void setReview(String review) { this.review = review; }
    public void setRecommend(String recommend) { this.recommend = recommend; }

    @Override
    public String toString() {
        return "商品名称: " + productName + "\n" +
               "库存数量: " + stock + "\n" +
               "用户评价: " + review + "\n" +
               "推荐商品: " + recommend;
    }
}

五、异常处理

5.1 异常处理方法

java 复制代码
package com.example.completablefuture;

import java.util.concurrent.CompletableFuture;

/**
 * 异常处理
 */
public class ExceptionHandling {

    public static void main(String[] args) throws Exception {

        // === 1. exceptionally - 异常处理 ===
        System.out.println("=== exceptionally ===");

        CompletableFuture<String> future1 = CompletableFuture
            .supplyAsync(() -> {
                if (true) {
                    throw new RuntimeException("发生异常");
                }
                return "正常结果";
            })
            .exceptionally(ex -> {
                System.out.println("捕获异常: " + ex.getMessage());
                return "异常时的默认值";
            });

        System.out.println("结果: " + future1.get());

        // === 2. handle - 同时处理正常和异常 ===
        System.out.println("\n=== handle ===");

        CompletableFuture<String> future2 = CompletableFuture
            .supplyAsync(() -> {
                if (Math.random() > 0.5) {
                    throw new RuntimeException("随机异常");
                }
                return "成功";
            })
            .handle((result, ex) -> {
                if (ex != null) {
                    System.out.println("处理异常: " + ex.getMessage());
                    return "异常处理结果";
                }
                System.out.println("处理正常结果: " + result);
                return result + " (已处理)";
            });

        System.out.println("结果: " + future2.get());

        // === 3. whenComplete - 完成时回调(不改变结果) ===
        System.out.println("\n=== whenComplete ===");

        CompletableFuture<String> future3 = CompletableFuture
            .supplyAsync(() -> "原始结果")
            .whenComplete((result, ex) -> {
                if (ex != null) {
                    System.out.println("发生异常: " + ex.getMessage());
                } else {
                    System.out.println("正常完成: " + result);
                }
            });

        System.out.println("结果: " + future3.get());

        // === 4. 异常传播 ===
        System.out.println("\n=== 异常传播 ===");

        CompletableFuture<String> future4 = CompletableFuture
            .supplyAsync(() -> {
                throw new RuntimeException("第一步异常");
            })
            .thenApply(s -> {
                System.out.println("这行不会执行");
                return s.toUpperCase();
            })
            .thenApply(s -> {
                System.out.println("这行也不会执行");
                return s + "!";
            })
            .exceptionally(ex -> {
                System.out.println("最终捕获: " + ex.getMessage());
                return "恢复值";
            });

        System.out.println("结果: " + future4.get());

        // === 5. 实战案例: API调用重试 ===
        demonstrateRetry();
    }

    /**
     * API调用重试示例
     */
    private static void demonstrateRetry() throws Exception {
        System.out.println("\n=== API调用重试 ===");

        int maxRetries = 3;

        CompletableFuture<String> result = retryAsync(() -> {
            // 模拟API调用
            if (Math.random() < 0.7) { // 70%失败率
                throw new RuntimeException("API调用失败");
            }
            return "API响应数据";
        }, maxRetries);

        System.out.println("最终结果: " + result.get());
    }

    /**
     * 异步重试方法
     */
    private static <T> CompletableFuture<T> retryAsync(
        java.util.concurrent.Callable<T> task, int maxRetries) {

        CompletableFuture<T> future = CompletableFuture.supplyAsync(() -> {
            try {
                return task.call();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });

        for (int i = 0; i < maxRetries; i++) {
            final int attempt = i + 1;
            future = future.exceptionally(ex -> {
                System.out.println("第" + attempt + "次重试...");
                try {
                    Thread.sleep(1000 * attempt); // 递增延迟
                    return task.call();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
        }

        return future.exceptionally(ex -> {
            System.out.println("重试" + maxRetries + "次后仍失败");
            throw new RuntimeException("最终失败: " + ex.getMessage());
        });
    }
}

六、线程池配置

6.1 自定义线程池

java 复制代码
package com.example.completablefuture;

import java.util.concurrent.*;

/**
 * 线程池配置
 */
public class ThreadPoolConfiguration {

    public static void main(String[] args) throws Exception {

        // === 1. 默认线程池(ForkJoinPool) ===
        System.out.println("=== 默认线程池 ===");
        System.out.println("处理器核心数: " + Runtime.getRuntime().availableProcessors());
        System.out.println("默认线程池大小: " + ForkJoinPool.commonPool().getParallelism());

        CompletableFuture.supplyAsync(() -> {
            System.out.println("默认线程池: " + Thread.currentThread().getName());
            return "Default";
        }).get();

        // === 2. 自定义线程池 ===
        System.out.println("\n=== 自定义线程池 ===");

        // 创建自定义线程池
        ThreadPoolExecutor customExecutor = new ThreadPoolExecutor(
            10,                      // 核心线程数
            20,                      // 最大线程数
            60L,                     // 空闲线程存活时间
            TimeUnit.SECONDS,        // 时间单位
            new LinkedBlockingQueue<>(100), // 任务队列
            new ThreadFactory() {    // 线程工厂
                private int count = 1;
                @Override
                public Thread newThread(Runnable r) {
                    return new Thread(r, "CustomThread-" + count++);
                }
            },
            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
        );

        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            System.out.println("自定义线程池: " + Thread.currentThread().getName());
            return "Custom";
        }, customExecutor);

        System.out.println("结果: " + future.get());

        // === 3. 线程池最佳实践 ===
        demonstrateBestPractices();

        customExecutor.shutdown();
    }

    /**
     * 线程池最佳实践
     */
    private static void demonstrateBestPractices() {
        System.out.println("\n=== 线程池最佳实践 ===");

        // CPU密集型任务: 核心数 + 1
        int cpuIntensive = Runtime.getRuntime().availableProcessors() + 1;
        System.out.println("CPU密集型推荐线程数: " + cpuIntensive);

        // IO密集型任务: 核心数 * 2
        int ioIntensive = Runtime.getRuntime().availableProcessors() * 2;
        System.out.println("IO密集型推荐线程数: " + ioIntensive);

        // 混合型任务: 根据实际情况调整
        System.out.println("\n线程池配置建议:");
        System.out.println("1. CPU密集型: 核心数+1");
        System.out.println("2. IO密集型: 核心数*2");
        System.out.println("3. 队列大小: 根据内存限制");
        System.out.println("4. 拒绝策略: CallerRunsPolicy(生产推荐)");
        System.out.println("5. 线程名称: 自定义ThreadFactory便于排查问题");
    }
}

七、实战案例:电商系统

7.1 商品详情页聚合服务

java 复制代码
package com.example.completablefuture.practice;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 实战案例: 电商商品详情页
 */
public class ProductDetailService {

    public static void main(String[] args) throws Exception {

        ProductDetailService service = new ProductDetailService();

        Long productId = 12345L;

        System.out.println("=== 加载商品详情页 ===\n");

        long start = System.currentTimeMillis();

        ProductDetailVO detail = service.getProductDetail(productId);

        long end = System.currentTimeMillis();

        System.out.println("\n" + detail);
        System.out.println("\n总耗时: " + (end - start) + "ms");
    }

    /**
     * 获取商品详情(并行聚合多个数据源)
     */
    public ProductDetailVO getProductDetail(Long productId) throws Exception {

        // 1. 查询商品基本信息(必须)
        CompletableFuture<ProductInfo> productFuture = CompletableFuture
            .supplyAsync(() -> queryProductInfo(productId));

        // 2. 查询价格信息(必须)
        CompletableFuture<PriceInfo> priceFuture = CompletableFuture
            .supplyAsync(() -> queryPriceInfo(productId));

        // 3. 查询库存信息(必须)
        CompletableFuture<StockInfo> stockFuture = CompletableFuture
            .supplyAsync(() -> queryStockInfo(productId));

        // 4. 查询商家信息(必须,依赖商品信息)
        CompletableFuture<MerchantInfo> merchantFuture = productFuture
            .thenCompose(product -> CompletableFuture.supplyAsync(
                () -> queryMerchantInfo(product.getMerchantId())));

        // 5. 查询评价信息(非必须)
        CompletableFuture<ReviewInfo> reviewFuture = CompletableFuture
            .supplyAsync(() -> queryReviewInfo(productId))
            .exceptionally(ex -> {
                System.out.println("评价服务异常,使用默认值");
                return new ReviewInfo(0.0, 0);
            });

        // 6. 查询推荐商品(非必须)
        CompletableFuture<RecommendInfo> recommendFuture = CompletableFuture
            .supplyAsync(() -> queryRecommendInfo(productId))
            .exceptionally(ex -> {
                System.out.println("推荐服务异常,使用默认值");
                return new RecommendInfo();
            });

        // 等待所有必须的数据
        CompletableFuture<Void> allRequired = CompletableFuture.allOf(
            productFuture, priceFuture, stockFuture, merchantFuture
        );

        // 等待必须数据完成
        allRequired.get();

        // 组装返回结果
        ProductDetailVO vo = new ProductDetailVO();
        vo.setProduct(productFuture.get());
        vo.setPrice(priceFuture.get());
        vo.setStock(stockFuture.get());
        vo.setMerchant(merchantFuture.get());

        // 非必须数据,尽量获取,超时则使用默认值
        try {
            vo.setReview(reviewFuture.getNow(new ReviewInfo(0.0, 0)));
            vo.setRecommend(recommendFuture.getNow(new RecommendInfo()));
        } catch (Exception e) {
            // 使用默认值
        }

        return vo;
    }

    // === 模拟各种查询服务 ===

    private ProductInfo queryProductInfo(Long productId) {
        sleep(300);
        System.out.println("✓ 查询商品信息");
        return new ProductInfo(productId, "iPhone 15 Pro", 1001L);
    }

    private PriceInfo queryPriceInfo(Long productId) {
        sleep(200);
        System.out.println("✓ 查询价格信息");
        return new PriceInfo(7999.0, 6999.0);
    }

    private StockInfo queryStockInfo(Long productId) {
        sleep(250);
        System.out.println("✓ 查询库存信息");
        return new StockInfo(150);
    }

    private MerchantInfo queryMerchantInfo(Long merchantId) {
        sleep(200);
        System.out.println("✓ 查询商家信息");
        return new MerchantInfo(merchantId, "Apple官方旗舰店");
    }

    private ReviewInfo queryReviewInfo(Long productId) {
        sleep(400);
        // 模拟偶尔异常
        if (ThreadLocalRandom.current().nextInt(10) < 2) {
            throw new RuntimeException("评价服务异常");
        }
        System.out.println("✓ 查询评价信息");
        return new ReviewInfo(4.8, 15000);
    }

    private RecommendInfo queryRecommendInfo(Long productId) {
        sleep(350);
        System.out.println("✓ 查询推荐信息");
        return new RecommendInfo();
    }

    private void sleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

// === 实体类 ===

class ProductDetailVO {
    private ProductInfo product;
    private PriceInfo price;
    private StockInfo stock;
    private MerchantInfo merchant;
    private ReviewInfo review;
    private RecommendInfo recommend;

    // Setters
    public void setProduct(ProductInfo product) { this.product = product; }
    public void setPrice(PriceInfo price) { this.price = price; }
    public void setStock(StockInfo stock) { this.stock = stock; }
    public void setMerchant(MerchantInfo merchant) { this.merchant = merchant; }
    public void setReview(ReviewInfo review) { this.review = review; }
    public void setRecommend(RecommendInfo recommend) { this.recommend = recommend; }

    @Override
    public String toString() {
        return "=== 商品详情 ===\n" +
               "商品: " + product.getName() + "\n" +
               "价格: ¥" + price.getSalePrice() + " (原价¥" + price.getOriginalPrice() + ")\n" +
               "库存: " + stock.getQuantity() + "\n" +
               "商家: " + merchant.getName() + "\n" +
               "评分: " + review.getScore() + "分 (" + review.getCount() + "条评价)";
    }
}

class ProductInfo {
    private Long id;
    private String name;
    private Long merchantId;

    public ProductInfo(Long id, String name, Long merchantId) {
        this.id = id;
        this.name = name;
        this.merchantId = merchantId;
    }

    public String getName() { return name; }
    public Long getMerchantId() { return merchantId; }
}

class PriceInfo {
    private Double originalPrice;
    private Double salePrice;

    public PriceInfo(Double originalPrice, Double salePrice) {
        this.originalPrice = originalPrice;
        this.salePrice = salePrice;
    }

    public Double getOriginalPrice() { return originalPrice; }
    public Double getSalePrice() { return salePrice; }
}

class StockInfo {
    private Integer quantity;

    public StockInfo(Integer quantity) {
        this.quantity = quantity;
    }

    public Integer getQuantity() { return quantity; }
}

class MerchantInfo {
    private Long id;
    private String name;

    public MerchantInfo(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getName() { return name; }
}

class ReviewInfo {
    private Double score;
    private Integer count;

    public ReviewInfo(Double score, Integer count) {
        this.score = score;
        this.count = count;
    }

    public Double getScore() { return score; }
    public Integer getCount() { return count; }
}

class RecommendInfo {
    // 推荐商品列表
}

八、实战案例:批量任务处理

8.1 批量数据导入

java 复制代码
package com.example.completablefuture.practice;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 实战案例: 批量数据导入
 */
public class BatchImportService {

    private static final int BATCH_SIZE = 100; // 每批处理100条

    public static void main(String[] args) throws Exception {

        BatchImportService service = new BatchImportService();

        // 模拟1000条数据
        List<DataRecord> records = new ArrayList<>();
        for (int i = 1; i <= 1000; i++) {
            records.add(new DataRecord(i, "数据" + i));
        }

        System.out.println("=== 批量数据导入 ===");
        System.out.println("总数据量: " + records.size() + "条\n");

        long start = System.currentTimeMillis();

        BatchImportResult result = service.batchImport(records);

        long end = System.currentTimeMillis();

        System.out.println("\n=== 导入结果 ===");
        System.out.println("成功: " + result.getSuccessCount() + "条");
        System.out.println("失败: " + result.getFailCount() + "条");
        System.out.println("总耗时: " + (end - start) + "ms");
    }

    /**
     * 批量导入数据
     */
    public BatchImportResult batchImport(List<DataRecord> records) throws Exception {

        // 分批处理
        List<List<DataRecord>> batches = splitBatch(records, BATCH_SIZE);

        System.out.println("分为 " + batches.size() + " 批处理\n");

        // 创建批量任务
        List<CompletableFuture<BatchResult>> futures = batches.stream()
            .map(batch -> CompletableFuture.supplyAsync(() -> processBatch(batch)))
            .collect(Collectors.toList());

        // 等待所有批次完成
        CompletableFuture<Void> allOf = CompletableFuture.allOf(
            futures.toArray(new CompletableFuture[0])
        );

        allOf.get();

        // 汇总结果
        int successCount = 0;
        int failCount = 0;

        for (CompletableFuture<BatchResult> future : futures) {
            BatchResult batchResult = future.get();
            successCount += batchResult.getSuccessCount();
            failCount += batchResult.getFailCount();
        }

        return new BatchImportResult(successCount, failCount);
    }

    /**
     * 处理单批数据
     */
    private BatchResult processBatch(List<DataRecord> batch) {
        System.out.println("[" + Thread.currentThread().getName() +
                          "] 处理批次,数量: " + batch.size());

        int success = 0;
        int fail = 0;

        for (DataRecord record : batch) {
            try {
                // 模拟数据处理
                Thread.sleep(10);

                // 模拟偶尔失败
                if (Math.random() < 0.05) { // 5%失败率
                    throw new RuntimeException("处理失败");
                }

                success++;
            } catch (Exception e) {
                fail++;
            }
        }

        System.out.println("[" + Thread.currentThread().getName() +
                          "] 批次完成,成功: " + success + ", 失败: " + fail);

        return new BatchResult(success, fail);
    }

    /**
     * 分批
     */
    private List<List<DataRecord>> splitBatch(List<DataRecord> records, int batchSize) {
        List<List<DataRecord>> batches = new ArrayList<>();

        for (int i = 0; i < records.size(); i += batchSize) {
            int end = Math.min(i + batchSize, records.size());
            batches.add(records.subList(i, end));
        }

        return batches;
    }
}

/**
 * 数据记录
 */
class DataRecord {
    private Integer id;
    private String data;

    public DataRecord(Integer id, String data) {
        this.id = id;
        this.data = data;
    }

    public Integer getId() { return id; }
    public String getData() { return data; }
}

/**
 * 批次结果
 */
class BatchResult {
    private int successCount;
    private int failCount;

    public BatchResult(int successCount, int failCount) {
        this.successCount = successCount;
        this.failCount = failCount;
    }

    public int getSuccessCount() { return successCount; }
    public int getFailCount() { return failCount; }
}

/**
 * 导入结果
 */
class BatchImportResult {
    private int successCount;
    private int failCount;

    public BatchImportResult(int successCount, int failCount) {
        this.successCount = successCount;
        this.failCount = failCount;
    }

    public int getSuccessCount() { return successCount; }
    public int getFailCount() { return failCount; }
}

九、性能优化与最佳实践

9.1 性能优化技巧

java 复制代码
package com.example.completablefuture.best;

import java.util.concurrent.*;

/**
 * 性能优化与最佳实践
 */
public class PerformanceOptimization {

    public static void main(String[] args) throws Exception {

        System.out.println("=== CompletableFuture最佳实践 ===\n");

        // === 1. 选择合适的方法 ===
        System.out.println("1. 选择合适的方法");
        System.out.println("   thenApply: 需要转换结果");
        System.out.println("   thenAccept: 只消费结果");
        System.out.println("   thenRun: 不关心结果");
        System.out.println("   选择最轻量的方法可以提升性能\n");

        // === 2. 使用自定义线程池 ===
        System.out.println("2. 使用自定义线程池");
        System.out.println("   ✓ 避免使用ForkJoinPool.commonPool()");
        System.out.println("   ✓ 根据任务类型配置线程池");
        System.out.println("   ✓ 设置有界队列防止OOM\n");

        // === 3. 避免阻塞操作 ===
        System.out.println("3. 避免阻塞操作");
        System.out.println("   ✗ 不要在回调中执行耗时IO操作");
        System.out.println("   ✓ 使用thenComposeAsync处理异步依赖\n");

        // === 4. 合理设置超时 ===
        demonstrateTimeout();

        // === 5. 批量任务优化 ===
        demonstrateBatchOptimization();

        // === 6. 异常处理 ===
        System.out.println("\n6. 异常处理最佳实践");
        System.out.println("   ✓ 使用exceptionally或handle处理异常");
        System.out.println("   ✓ 避免异常被吞没");
        System.out.println("   ✓ 记录完整的异常堆栈");
    }

    /**
     * 超时控制
     */
    private static void demonstrateTimeout() throws Exception {
        System.out.println("4. 超时控制");

        CompletableFuture<String> slowTask = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "慢任务结果";
        });

        try {
            // JDK 9+支持超时
            // String result = slowTask.get(2, TimeUnit.SECONDS);

            // JDK 8可以使用这种方式
            String result = slowTask
                .applyToEither(
                    timeout(2, TimeUnit.SECONDS),
                    s -> s
                )
                .get();

            System.out.println("   结果: " + result);
        } catch (TimeoutException e) {
            System.out.println("   ✓ 任务超时,已取消");
            slowTask.cancel(true);
        } catch (Exception e) {
            System.out.println("   ✗ 任务超时");
        }
    }

    /**
     * 创建超时Future
     */
    private static <T> CompletableFuture<T> timeout(long timeout, TimeUnit unit) {
        CompletableFuture<T> future = new CompletableFuture<>();
        Executors.newScheduledThreadPool(1).schedule(
            () -> future.completeExceptionally(new TimeoutException()),
            timeout,
            unit
        );
        return future;
    }

    /**
     * 批量任务优化
     */
    private static void demonstrateBatchOptimization() {
        System.out.println("\n5. 批量任务优化");
        System.out.println("   ✓ 分批处理,避免创建过多线程");
        System.out.println("   ✓ 使用allOf等待批次完成");
        System.out.println("   ✓ 控制并发度,避免资源耗尽");
        System.out.println("   示例:");
        System.out.println("   - 1000个任务");
        System.out.println("   - 分10批,每批100个");
        System.out.println("   - 逐批执行,降低并发压力");
    }
}

十、常见问题与陷阱

10.1 常见陷阱

java 复制代码
package com.example.completablefuture.best;

import java.util.concurrent.CompletableFuture;

/**
 * 常见问题与陷阱
 */
public class CommonPitfalls {

    public static void main(String[] args) throws Exception {

        System.out.println("=== CompletableFuture常见陷阱 ===\n");

        // === 陷阱1: 忘记处理异常 ===
        System.out.println("陷阱1: 异常被吞没");

        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
            throw new RuntimeException("异常");
        }).thenApply(s -> s.toUpperCase()); // 不会执行

        try {
            future1.get(); // 这里才会抛出异常
        } catch (Exception e) {
            System.out.println("  ✗ 异常: " + e.getCause().getMessage());
        }

        // 正确做法
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            throw new RuntimeException("异常");
        }).exceptionally(ex -> {
            System.out.println("  ✓ 捕获并处理异常: " + ex.getMessage());
            return "默认值";
        });

        System.out.println("  结果: " + future2.get());

        // === 陷阱2: 在回调中阻塞 ===
        System.out.println("\n陷阱2: 在回调中阻塞");

        // ✗ 错误: 阻塞回调线程
        CompletableFuture.supplyAsync(() -> "Step1")
            .thenApply(s -> {
                try {
                    Thread.sleep(5000); // 阻塞
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return s + " Step2";
            });

        System.out.println("  ✗ 不要在回调中执行耗时操作");

        // ✓ 正确: 使用Async方法
        CompletableFuture.supplyAsync(() -> "Step1")
            .thenApplyAsync(s -> {
                // 这会在另一个线程执行
                return s + " Step2";
            });

        System.out.println("  ✓ 使用thenApplyAsync");

        // === 陷阱3: 忘记指定线程池 ===
        System.out.println("\n陷阱3: 使用公共线程池");
        System.out.println("  ✗ 默认使用ForkJoinPool.commonPool()");
        System.out.println("  ✗ 可能被其他任务影响");
        System.out.println("  ✓ 使用自定义线程池隔离资源");

        // === 陷阱4: 链式调用中断 ===
        System.out.println("\n陷阱4: 链式调用中断");

        CompletableFuture<String> broken = CompletableFuture
            .supplyAsync(() -> {
                throw new RuntimeException("第一步失败");
            })
            .thenApply(s -> {
                System.out.println("这行不会执行");
                return s.toUpperCase();
            })
            .thenApply(s -> {
                System.out.println("这行也不会执行");
                return s + "!";
            });

        System.out.println("  ✗ 链式调用会因异常中断");
        System.out.println("  ✓ 使用handle或exceptionally处理");

        // === 陷阱5: 忘记get()或join() ===
        System.out.println("\n陷阱5: 任务未执行完就退出");

        CompletableFuture.runAsync(() -> {
            try {
                Thread.sleep(100);
                System.out.println("  这行可能不会执行");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 如果主线程退出,异步任务可能未完成
        // 正确做法: future.get() 或 future.join()

        Thread.sleep(200); // 等待演示

        // === 最佳实践总结 ===
        printBestPractices();
    }

    /**
     * 最佳实践总结
     */
    private static void printBestPractices() {
        System.out.println("\n=== 最佳实践总结 ===");

        System.out.println("\n✓ 推荐做法:");
        System.out.println("1. 使用自定义线程池");
        System.out.println("2. 处理所有异常(exceptionally/handle)");
        System.out.println("3. 设置超时时间");
        System.out.println("4. 合理使用Async后缀方法");
        System.out.println("5. 批量任务分批处理");
        System.out.println("6. 记录详细日志");

        System.out.println("\n✗ 避免做法:");
        System.out.println("1. 在回调中执行阻塞操作");
        System.out.println("2. 忽略异常处理");
        System.out.println("3. 过度使用CompletableFuture");
        System.out.println("4. 创建过多线程");
        System.out.println("5. 循环依赖");
    }
}

总结

核心知识点回顾

本文深入探讨了JDK 8 CompletableFuture,主要内容包括:

  1. 基础概念

    • Future的局限性
    • CompletableFuture的优势
    • 核心方法分类
  2. 基本操作

    • 创建CompletableFuture
    • 结果处理与转换
    • 链式调用
  3. 高级特性

    • 多任务组合(thenCompose/thenCombine/allOf/anyOf)
    • 异常处理(exceptionally/handle/whenComplete)
    • 线程池配置
  4. 实战应用

    • 电商商品详情页数据聚合
    • 批量数据导入处理
    • API重试机制
  5. 性能优化

    • 线程池配置建议
    • 超时控制
    • 批量任务优化

Future对比

维度 Future CompletableFuture
手动完成
链式调用
多任务组合
异常处理
非阻塞
回调支持

使用场景

diff 复制代码
适用场景:
+---------------------------+
| ✓ 并行调用多个服务        |
| ✓ 数据聚合(商品详情页)    |
| ✓ 批量任务处理            |
| ✓ 异步日志、通知          |
| ✓ 超时控制                |
| ✓ 降级与容错              |
+---------------------------+

不适用场景:
+---------------------------+
| ✗ 简单的顺序调用          |
| ✗ 需要事务一致性          |
| ✗ 复杂的状态管理          |
| ✗ 过度的嵌套依赖          |
+---------------------------+

线程池配置建议

java 复制代码
// CPU密集型
int cpuThreads = Runtime.getRuntime().availableProcessors() + 1;

// IO密集型
int ioThreads = Runtime.getRuntime().availableProcessors() * 2;

// 自定义线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize,           // 核心线程数
    maximumPoolSize,        // 最大线程数
    60L,                    // 空闲存活时间
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(1000),  // 有界队列
    new NamedThreadFactory("async-"),  // 自定义名称
    new ThreadPoolExecutor.CallerRunsPolicy()  // 拒绝策略
);
相关推荐
leonardee5 小时前
Spring Security安全框架原理与实战
java·后端
q***5185 小时前
Spring Cloud gateway 路由规则
java
空空kkk5 小时前
SpringMVC框架——入门
java·spring
liyi_hz20085 小时前
云原生 + 国产化适配:O2OA (翱途)开发平台后端技术栈深度解析
java·后端·开源软件
⑩-5 小时前
缓存穿透,击穿,雪崩
java·redis
合作小小程序员小小店5 小时前
web网页开发,在线%考试管理%系统,基于Idea,html,css,jQuery,java,jsp,servlet,mysql。
java·前端·intellij-idea
程序媛_MISS_zhang_01106 小时前
vant-ui中List 组件可以与 PullRefresh 组件结合使用,实现下拉刷新的效果
java·linux·ui
曹牧6 小时前
Java中处理URL转义并下载PDF文件
java·开发语言·pdf
雾山大叔6 小时前
Python学习 - 面向对象学习-文件分类小测试
java·前端·spring
Eric_Makabaka6 小时前
计算机网络重要知识点
java·网络·计算机网络