Java 8 CompletableFuture延迟计算控件

时间:2016-07-17 11:54:09

标签: java java-8 lazy-evaluation completable-future

我有一个关于CompletableFuture的问题及其对延迟计算的可能用法。

对于此任务来说,它似乎是RunnableFuture的绝佳替代品,因为可以轻松创建任务链并完全控制每个链接。我仍然发现很难控制何时进行计算。

如果我只使用CompletableFuture方法或类似方法创建supplyAssync,则可以。它耐心等待我拨打getjoin方法进行计算。但是,如果我尝试使用whenComposehandle或任何其他方法创建实际链,评估会立即开始,这非常令人沮丧。

当然,我总是可以在链的开头放置一些阻塞任务,并在我准备开始计算时释放块,但这似乎有点难看。有人知道如何控制CompletableFuture实际运行的时间。

4 个答案:

答案 0 :(得分:4)

您在RunnableFutureCompletableFuture之间存在概念差异。

  • RunnableFuture实现将任务作为输入并保留在其上。它在您调用run方法时运行任务。
  • CompletableFuture无法保留任务。它只知道任务的结果。它有三种状态:完成不完整异常完成(失败)。

CompletableFuture.supplyAsync是一种工厂方法,可为您提供不完整的CompletableFuture。它还会计划一项任务,该任务在完成后会将其结果传递给CompletableFuture complete方法。换句话说,supplyAsync给你的未来知道关于任务的任何事情,并且无法控制任务的运行时间。

要以您描述的方式使用CompletableFuture,您需要创建一个子类:

public class RunnableCompletableFuture<T> extends CompletableFuture<T> implements RunnableFuture<T> {
    private final Callable<T> task;

    public RunnableCompletableFuture(Callable<T> task) {
        this.task = task;
    }

    @Override
    public void run() {
        try {
            complete(task.call());
        } catch (Exception e) {
            completeExceptionally(e);
        }
    }
}

答案 1 :(得分:1)

CompletableFuture是一种推式设计,即一旦可用,结果就会被推送到相关任务。这也意味着消耗的侧链仍然被执行,这可能会产生副作用。

你想要的是一种拉动设计,其祖先只会在消耗数据时被拉入。 这将是一个根本不同的设计,因为非消费树的副作用永远不会发生。

当然,如果有足够的扭曲,CF可以做你想做的事情,但是你应该研究fork-join框架,它允许你只运行你所依赖的计算而不是压低结果。

答案 2 :(得分:0)

处理问题的一种简单方法是将CompletableFuture包装在具有惰性的东西中。您可以使用供应商甚至Java 8 Stream。

答案 3 :(得分:0)

已经晚了,但是如何对链中的第一个CompletableFuture使用构造函数呢?

CompletableFuture<Object> cf = new CompletableFuture<>();

// compose the chain
cf.thenCompose(sometask_here);

// later starts the chain with
cf.complete(anInputObject);