深入理解Java CompletableFuture的使用

2023-12-27 10:47:49

深入理解Java CompletableFuture的使用

解析:

CompletableFuture 是 Java 中用于异步编程的工具,提供了丰富的方法来处理异步任务。下面解析一些CompletableFuture的常用方法:

1. runAsyncsupplyAsync

  • runAsync 用于执行没有返回值的异步任务。

    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
        // 异步任务的逻辑
    });
    
  • supplyAsync 用于执行有返回值的异步任务。

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        // 异步任务的逻辑
        return "Result";
    });
    

2. thenApplythenAccept

  • thenApply 对异步任务的结果进行转换,返回一个新的 CompletableFuture

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
        .thenApply(s -> s + " World");
    
  • thenAccept 对异步任务的结果进行消费,没有返回值。

    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello")
        .thenAccept(s -> System.out.println("Result: " + s));
    

3. thenComposethenCombine

  • thenCompose 组合两个异步任务,返回一个新的 CompletableFuture

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
        .thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World"));
    
  • thenCombine 组合两个异步任务的结果,返回一个新的 CompletableFuture

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
        .thenCombine(CompletableFuture.supplyAsync(() -> " World"), (s1, s2) -> s1 + s2);
    

4. exceptionallyhandle

  • exceptionally 处理异步任务的异常情况,返回一个默认值。

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        // 异步任务的逻辑,可能抛出异常
        throw new RuntimeException("Error");
    }).exceptionally(ex -> "Default Value");
    
  • handle 处理异步任务的结果和异常,返回一个新的 CompletableFuture

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        // 异步任务的逻辑,可能抛出异常
        throw new RuntimeException("Error");
    }).handle((result, ex) -> result != null ? result : "Default Value");
    

5. allOfanyOf

  • allOf 等待所有给定的 CompletableFuture 完成。

    CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(future1, future2, future3);
    
  • anyOf 等待任意一个给定的 CompletableFuture 完成。

    CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2, future3);
    

6. joinget

  • join 获取异步任务的结果,没有抛出检查异常。

    String result = CompletableFuture.supplyAsync(() -> "Hello").join();
    
  • get 获取异步任务的结果,可能抛出 ExecutionExceptionInterruptedException

    String result = CompletableFuture.supplyAsync(() -> "Hello").get();
    

这些方法提供了丰富的功能,让你能够更灵活地处理异步任务的执行结果、异常和组合。在实际应用中,根据具体场景和需求选择合适的方法组合使用,能够编写出高效、健壮且易读的异步代码。

7. thenRunthenRunAsync

  • thenRun 在异步任务完成后执行一个没有输入参数且没有返回值的操作。

    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello")
        .thenRun(() -> System.out.println("Async task completed."));
    
  • thenRunAsync 在异步任务完成后执行一个没有输入参数且没有返回值的操作,可以指定执行的线程池。

    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello")
        .thenRunAsync(() -> System.out.println("Async task completed."),
                      Executors.newCachedThreadPool());
    

8. thenCombineAsyncthenAcceptBothAsync

  • thenCombineAsync 组合两个异步任务的结果,并使用指定的 Executor 执行。

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
        .thenCombineAsync(CompletableFuture.supplyAsync(() -> " World"),
                          (s1, s2) -> s1 + s2,
                          Executors.newCachedThreadPool());
    
  • thenAcceptBothAsync 组合两个异步任务的结果,并在两个任务都完成后执行一个消费者操作。

    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello")
        .thenAcceptBothAsync(CompletableFuture.supplyAsync(() -> " World"),
                             (s1, s2) -> System.out.println(s1 + s2),
                             Executors.newCachedThreadPool());
    

9. cancelisCancelled

  • cancel 取消异步任务的执行。

    boolean cancelled = future.cancel(true);
    
  • isCancelled 判断异步任务是否被取消。

    boolean isCancelled = future.isCancelled();
    

10. thenComposeAsyncthenAcceptAsync

  • thenComposeAsync 类似于 thenCompose,用于组合两个异步任务,但可以指定执行的线程池。

    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello")
        .thenComposeAsync(s -> CompletableFuture.supplyAsync(() -> s + " World"),
                          Executors.newCachedThreadPool());
    
  • thenAcceptAsync 类似于 thenAccept,对异步任务的结果进行消费,可以指定执行的线程池。

    CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> "Hello")
        .thenAcceptAsync(s -> System.out.println("Result: " + s),
                          Executors.newCachedThreadPool());
    

这些方法提供了更多的灵活性和控制,允许你在处理异步任务时更精细地指定操作和执行环境。在实际开发中,根据具体需求选择合适的方法进行组合,可以更好地应对不同的异步编程场景。

举例:

下面我们将通过一个例子详细解释CompletableFuture的使用,并使用博客格式输出。

示例:并行下载图片

假设我们有一个需求:从多个网站并行下载图片,并在所有图片下载完成后进行一些处理。以下是使用CompletableFuture实现的示例代码。

import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class ImageDownloader {

    // 模拟图片下载
    private static byte[] downloadImage(String imageUrl) {
        // 实际的图片下载逻辑
        System.out.println("Downloading image from " + imageUrl);
        // 返回一个假设的图片字节数组
        return new byte[]{1, 2, 3, 4, 5};
    }

    // 模拟图片处理
    private static void processImage(byte[] imageBytes) {
        // 实际的图片处理逻辑
        System.out.println("Processing image: " + Arrays.toString(imageBytes));
    }

    public static void main(String[] args) {
        List<String> imageUrls = Arrays.asList(
                "https://example.com/image1.jpg",
                "https://example.com/image2.jpg",
                "https://example.com/image3.jpg"
        );

        try {
            // 使用CompletableFuture并行下载图片
            CompletableFuture<Void> allOf = CompletableFuture.allOf(
                    imageUrls.stream()
                            .map(url -> CompletableFuture.supplyAsync(() -> downloadImage(url))
                                    .thenAcceptAsync(ImageDownloader::processImage))
                            .toArray(CompletableFuture[]::new)
            );

            // 等待所有图片下载完成
            allOf.get();

            // 所有图片下载完成后的处理
            System.out.println("All images downloaded and processed successfully!");

        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

解析与说明:

  1. downloadImage方法:

    private static byte[] downloadImage(String imageUrl) {
        // 实际的图片下载逻辑
        System.out.println("Downloading image from " + imageUrl);
        // 返回一个假设的图片字节数组
        return new byte[]{1, 2, 3, 4, 5};
    }
    

    downloadImage 方法模拟从指定URL下载图片的逻辑。

  2. processImage方法:

    private static void processImage(byte[] imageBytes) {
        // 实际的图片处理逻辑
        System.out.println("Processing image: " + Arrays.toString(imageBytes));
    }
    

    processImage 方法模拟对下载的图片进行处理的逻辑。

  3. 使用CompletableFuture并行下载图片:

    CompletableFuture<Void> allOf = CompletableFuture.allOf(
            imageUrls.stream()
                    .map(url -> CompletableFuture.supplyAsync(() -> downloadImage(url))
                            .thenAcceptAsync(ImageDownloader::processImage))
                    .toArray(CompletableFuture[]::new)
    );
    

    通过 CompletableFuture.allOf 方法,将所有图片的下载任务组合在一起,以便在所有图片下载完成后执行后续的操作。

  4. 等待所有图片下载完成:

    allOf.get();
    

    通过 allOf.get() 等待所有的图片下载任务完成。在实际应用中,可以根据需要添加超时等逻辑。

  5. 所有图片下载完成后的处理:

    System.out.println("All images downloaded and processed successfully!");
    

    所有图片下载完成后,输出提示信息。

这个示例展示了如何使用CompletableFuture并行下载多个图片,可以通过类似的方式处理其他异步任务。这种方式能够提高系统的性能和响应速度。

文章来源:https://blog.csdn.net/cxkjntm123/article/details/135227016
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。