Java短路CompletableFuture

时间:2018-02-02 17:33:09

标签: java multithreading completable-future

我正在尝试根据具体情况找到跳过CompletableFuture的方法。

例如

public CompletableFuture<Void> delete(Long id) {
    CompletableFuture<T> preFetchCf = get(id);
    CompletableFuture<Boolean> cf1 = execute();

    /*This is where I want different execution path, if result of this future is true go further, else do not*/

    // Execute this only if result of cf1 is true
    CompletableFuture<T> deleteCf = _delete(id);
    // Execute this only if result of cf1 is true
    CompletableFuture<T> postDeleteProcess = postDelete(id);
}

实现这一目标的好方法是什么?

2 个答案:

答案 0 :(得分:1)

我将准备一个与您在问题中使用的示例不同的示例,因为从读者的角度来看,您的代码的意图并不十分明确。

首先假设现有的CompletableFuture<String>提供星球大战角色的名称。

CompletableFuture<String> character = CompletableFuture.completedFuture("Luke");

现在,想象一下我还有另外两个CompletableFuture代表我可能想要遵循的不同路径,这取决于第一个可完成的未来是否提供了一个绝地角色。

Supplier<CompletableFuture<String>> thunk1 = () -> CompletableFuture.completedFuture("This guy is a Jedi");
Supplier<CompletableFuture<String>> thunk2 = () -> CompletableFuture.completedFuture("This guy is not a Jedi");

请注意,我将CompletableFuture包裹在一个Supplier中,以避免他们急切地评估(这是thunk这个概念)。

现在,我去了我的异步链:

character.thenApply(c -> isJedi(c))
            .thenCompose(isJedi -> isJedi ? thunk1.get() : thunk2.get())
            .whenComplete((answer, error) -> System.out.println(answer));

使用thenCompose让我根据布尔结果选择路径。在那里,我评估其中一个thunk并使其为我关心的路径创建一个新的CompletableFuture

这将打印到屏幕"This guys is a Jedi"

所以,我相信你要找的是thenCompose方法。

答案 1 :(得分:0)

不确定我是否理解你的目标,但为什么你不会像你在评论中所说的那样选择未来的链接?这样的事情,只是为了说明:

public class AppTest {
    @Test
    public void testCompletableFutures() {
        Integer id = (int) Math.random() * 1000;

        CompletableFuture<Void> testing = AppTest.execute()
                .thenAcceptAsync(result -> {
                    System.out.println("Result is: " + result);
                    if(result)
                        AppTest.delete(id);
                    else
                        throw new RuntimeException("Execution failed");
                })
                .thenApplyAsync(result -> AppTest.postDelete())
                .thenAcceptAsync(postDeleteResult -> {
                    if(postDeleteResult)
                        System.out.println("Post delete cleanup success");
                    else
                        throw new RuntimeException("Post delete failed");
                });
    }

    private static boolean postDelete() {
        System.out.println("Post delete cleanup");
        return Math.random() > 0.3;
    }

    private static CompletableFuture<Boolean> delete(int i) {
        System.out.println("Deleting id = " + i);
        return CompletableFuture.completedFuture(true);
    }

    private static CompletableFuture<Boolean> execute() {
        return CompletableFuture.supplyAsync(() -> Math.random() > 0.5);
    }
}

当然,这并没有太多的现实意义,但我认为这有助于展示一个概念。

如果你想根据结果跳过execute之后的第二个电话,那么显然不可能,因为你需要那个结果。关键在于你是否跳过它并不重要,因为它是异步的,你不会阻止等待那个结果。