CompletableFuture实战:构建高效异步工作流

独步天下 2020-04-15 ⋅ 12 阅读

在Java中,CompletableFuture是一种强大的异步编程工具,它提供了许多方便的方法来构建高效的异步工作流。本文将介绍CompletableFuture的基本概念,并通过实例演示如何使用CompletableFuture来构建高效的异步工作流。

异步编程和CompletableFuture

在传统的同步编程中,代码按照顺序依次执行,每个任务都需要等待前一个任务完成后才能执行。这种方式在一些场景下会导致效率低下,因为某些任务可能是可以并行执行的。

异步编程则允许我们在执行某个任务时,不必等待其完全执行完成,而是可以继续执行其他任务。这种方式可以提升性能并提高响应速度。

CompletableFuture是Java 8引入的一种用于异步编程的工具类。它提供了丰富的方法和操作符,可以方便地构建异步工作流,实现任务的串联、并行执行、等待多个任务完成等。

CompletableFuture的基本用法

CompletableFuture可以通过CompletableFuture.supplyAsync()方法创建一个异步任务。该方法接受一个Supplier函数,用于执行任务并返回结果。

下面是一个简单的例子,演示了如何使用CompletableFuture创建一个异步任务,并使用thenApply()方法对结果进行处理:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 执行耗时的任务
    return "Hello";
}).thenApply(result -> result + " World");

future.get(); // 获取执行结果,如果任务还没有完成,则会阻塞等待

在上面的例子中,supplyAsync()方法会在一个新的线程中执行其参数函数,并返回一个CompletableFuture对象。我们可以通过调用thenApply()方法来链式地处理结果,该方法会在任务完成后以lambda表达式的形式接收结果并进行处理。

构建异步工作流

CompletableFuture提供了一系列方法来构建异步工作流。通过这些方法,我们可以方便地串联多个任务,实现任务的并行执行、条件执行等。

串联任务

使用thenApply()方法可以简单地串联多个任务。每个thenApply()方法都是在上一个任务完成后调用,并且上一个任务的执行结果会作为参数传递给当前任务。

下面是一个示例,展示了如何通过thenApply()方法串联两个任务:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    // 执行第一个任务
    return "Hello";
}).thenApply(result -> {
    // 执行第二个任务,参数result是上一个任务的结果
    return result + " World";
});

future.get(); // Hello World

并行执行任务

有时候,我们希望多个任务可以并行执行,以提高效率。CompletableFuture提供了一系列thenCombine()allOf()anyOf()等方法来支持并行执行任务。

thenCombine()方法可以组合两个任务的结果,并在两个任务都完成后触发回调:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    // 执行任务1
    return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    // 执行任务2
    return "World";
});

CompletableFuture<String> combinedFuture = future1.thenCombine(future2, (result1, result2) -> {
    // 对结果进行组合处理
    return result1 + " " + result2;
});

combinedFuture.get(); // Hello World

allOf()方法接收一个CompletableFuture数组,并在所有任务完成后触发回调。下面的例子展示了如何使用allOf()方法等待并组合多个任务的结果:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    // 执行任务1
    return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    // 执行任务2
    return "World";
});

CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2);
CompletableFuture<List<String>> combinedFuture = allFutures.thenApply(v -> {
    return Stream.of(future1, future2)
        .map(CompletableFuture::join) // 获取任务结果
        .collect(Collectors.toList());
});

combinedFuture.get(); // [Hello, World]

anyOf()方法接收一个CompletableFuture数组,并在任一任务完成后触发回调。下面的例子演示了如何使用anyOf()方法只获取最快完成的任务结果:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    // 执行任务1
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    // 执行任务2
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "World";
});

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

anyOfFuture.get(); // Hello

条件执行任务

有时候,我们希望根据任务的执行结果来决定下一步的操作。CompletableFuture提供了一些方法来支持条件执行任务,比如thenApplyAsync()thenCompose()thenAcceptBoth()等。

thenApplyAsync()方法可以指定一个Executor线程池,用于在任务完成后执行回调。这样可以避免回调方法阻塞主线程。

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    // 执行任务1
    return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    // 执行任务2
    return "World";
});

CompletableFuture<String> conditionalFuture = future1.thenApplyAsync(result1 -> {
    if (result1.equals("Hello")) {
        return result1.toUpperCase();
    } else {
        return "Invalid";
    }
});

conditionalFuture.get(); // HELLO

thenCompose()方法可以在一个任务完成后,将其结果作为参数传递给下一个任务。

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    // 执行任务1
    return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    // 执行任务2
    return " World";
});

CompletableFuture<String> composedFuture = future1.thenCompose(result1 -> {
    // 在任务1完成后执行任务2,并将任务1的结果和任务2的结果组合
    return CompletableFuture.supplyAsync(() -> result1 + " World");
});

composedFuture.get(); // Hello World

thenAcceptBoth()方法可以在两个任务都完成后触发回调,将两个任务的结果作为参数传递给回调方法。

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    // 执行任务1
    return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    // 执行任务2
    return " World";
});

CompletableFuture<Void> acceptBothFuture = future1.thenAcceptBoth(future2, (result1, result2) -> {
    // 对任务1和任务2的结果进行处理
    System.out.println(result1 + result2); // Hello World
});

acceptBothFuture.get(); // null

总结

CompletableFuture是Java 8引入的一种强大的异步编程工具,它提供了丰富的方法来构建高效的异步工作流。本文介绍了CompletableFuture的基本概念,并通过实例演示了如何使用CompletableFuture来串联任务、并行执行任务、条件执行任务等。

使用CompletableFuture可以提高代码的效率和响应能力,同时提供了更好的编程体验和可读性。在实际开发中,我们可以根据具体需求选择合适的方法和操作符来构建异步工作流,从而更好地利用多核处理器和异步执行任务。


全部评论: 0

    我有话说: