首页 > 解决方案 > 如何确保 CompletableFuture 在执行一段代码之前完全完成?

问题描述

我有这段代码,我有两个问题。

  1. 我不确定为什么我会看到 TimeoutException,因为任何地方都没有阻塞。
  2. 我想要实现的Collector是我有一个类将进入收集一堆指标,并且在CompletableFuture完全完成之后我将执行Collector以发布指标。finally保证它会最后执行,因为我认为应该.get()被阻止直到它完成?
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.function.Supplier;

public class FutureWithCollector
{
    public static void main(String[] args) throws ExecutionException, InterruptedException
    {
        Collector collector = new Collector();
        finalize(() -> query(collector), collector);
    }

    private static void finalize(Supplier<CompletableFuture<String>> submission, Collector collector) throws ExecutionException, InterruptedException
    {
        ExecutorService executorService = Executors.newFixedThreadPool(1);
        CompletableFuture<String> s = CompletableFuture.supplyAsync(submission, executorService).thenCompose(Function.identity());
        try {
            String result = s.get(1000, TimeUnit.MILLISECONDS);
            System.out.println(result);
        } catch (TimeoutException e) {
            e.printStackTrace();
        } finally {
            System.out.println(collector.getI());
        }
    }

    private static CompletableFuture<String> query(Collector collector)
    {
        CompletableFuture<String> future = new CompletableFuture<>();
        return future.thenApply(r -> {
            collector.collectStuff();
            return "Hello";
        });
    }

}

class Collector
{
    private volatile int i;

    public void collectStuff()
    {
        i++;
    }

    public int getI()
    {
        return i;
    }
}

输出

java.util.concurrent.TimeoutException
    at java.util.concurrent.CompletableFuture.timedGet(CompletableFuture.java:1771)
    at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1915)
    at FutureWithCollector.finalize(FutureWithCollector.java:23)
    at FutureWithCollector.main(FutureWithCollector.java:15)
0

标签: javacompletable-future

解决方案


这很简单,只需更改您的一种方法:

 private static CompletableFuture<String> query(Collector collector) {

    return CompletableFuture.supplyAsync(() -> {
        collector.collectStuff(); 
        return "hello";
    });

}

你正在做:

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

记录为:

创建一个新的不完整的CompletableFuture。

本质上,没有人完成这个CompletableFuture,所以你总是会得到一个超时,不管它有多大。


您也可以稍微更改您的代码。如果您想要run某事,请明确地说:

private static CompletableFuture<Void> query(Collector collector) {
     return CompletableFuture.runAsync(collector::collectStuff);
}

然后请注意collectStuff增量 a volatile,但这些增量不是原子的。

而且您始终可以使用joinget不是处理已检查的异常(join假设没有超时)。


推荐阅读