【问题标题】:using Supplier in CompletableFuture yields different result than using lambda在 CompletableFuture 中使用 Supplier 会产生与使用 lambda 不同的结果
【发布时间】:2016-12-27 10:25:41
【问题描述】:

我创建了一个读取文本文件并使用CompletableFuture 包装调用的小示例。

public class Async {
    public static void main(String[] args) throws Exception {
        CompletableFuture<String> result = ReadFileUsingLambda(Paths.get("path/to/file"));
        result.whenComplete((ok, ex) -> {
            if (ex == null) {
                System.out.println(ok);
            } else {
                ex.printStackTrace();
            }
        });
    }

    public static CompletableFuture<String> ReadFileUsingSupplier(Path file) throws Exception {
        return CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                try {
                    return new String(Files.readAllBytes(file));
                } catch (IOException e) {
                    e.printStackTrace();
                    return "test";
                }
            }
        }, ForkJoinPool.commonPool());
    }

    public static CompletableFuture<String> ReadFileUsingLambda(Path file) throws Exception {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return new String(Files.readAllBytes(file));
            } catch (IOException e) {
                e.printStackTrace();
                return "test";
            }
        } , ForkJoinPool.commonPool());
    }
}

此代码不返回任何内容。它执行并且“没有任何反应”,没有错误或输出。如果我调用ReadFileUsingSupplier 而不是ReadFileUsingLambda,那么我会在控制台中打印文件内容!

对我来说这没有任何意义,因为 lambda 是编写内联函数的简写,它不应该改变行为,但在这个例子中它显然改变了。

【问题讨论】:

    标签: java lambda java-8 completable-future


    【解决方案1】:

    我认为这只是执行时间的问题 - lambda 可能需要更多时间才能执行,从而允许程序在您完成读取文件之前退出。

    试试这个:

    • ReadFileUsingSupplier 的try 块中添加Thread.sleep(1000); 作为第一条语句,您将看不到任何输出
    • 在使用 ReadFileUsingLambda 时在 main 末尾添加 Thread.sleep(1000);,您将看到预期的输出

    为确保您的 main 在未来完成之前不会退出,您可以调用:

    result.join();
    

    【讨论】:

    • 谢谢。这成功了,但接下来我如何确保我的程序在从 CompletableFuture 获得结果之前不会退出
    • @SulAga 您可以直接致电result.get()result.join()
    • 所以加入或获取是阻塞调用?它是主线程还是 CompletableFuture 线程上的阻塞?这是一个问题,即阻塞
    • @SulAga 它在调用它的线程上阻塞——如果你只是在main 的末尾添加result.join(),它将阻塞主线程。
    【解决方案2】:

    如前所述,无论哪种情况,您都需要 result.join() 以避免主线程退出太快。

    似乎在 JVM 预热时使用 lambdas 与匿名闭包会受到惩罚,此后性能是相同的。我在 another SO thread 上找到了此信息 - 反过来链接 a performance study by Oracle

    作为旁注,使用 Thread.sleep() 来解决奇怪的时间问题从来都不是一个好主意。当您或其他人重新阅读时,找出原因并采取适当的措施会更加清晰,例如

    System.out.println(result.get(5, TimeUnit.SECONDS));
    

    这使您也可以放弃 .join()。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-24
      • 2016-11-02
      • 1970-01-01
      • 2019-03-05
      • 1970-01-01
      • 2017-12-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多