在CompletableFuture中使用Supplier会产生与使用lambda不同的结果

时间:2016-12-27 10:25:42

标签: java lambda java-8 completable-future

我创建了一个小例子,用于读取文本文件并使用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());
    }
}

此代码不返回任何内容。它执行并且&#34;没有任何事情发生&#34;,没有错误或输出。如果我拨打ReadFileUsingSupplier而不是ReadFileUsingLambda,那么我会在控制台中打印文件内容!

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

2 个答案:

答案 0 :(得分:4)

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

试试这个:

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

要确保您的主管在未来完成之前不退出,您可以致电:

result.join();

答案 1 :(得分:2)

如上所述,在任何一种情况下都需要result.join()以避免主线程退出太快。

在JVM升温时,使用lambdas与匿名闭包似乎是一种惩罚,此后性能是相同的。我在another SO thread上找到了此信息,而后者又链接了a performance study by Oracle

作为旁注,Thread.sleep()修复奇怪的计时问题并不是一个好主意。当您或其他人重新阅读时,弄清楚原因并采取适当的措施会更加清晰,例如

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

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