gpt4 book ai didi

java - Java 作用域中的异步 lambda 如何处理局部变量

转载 作者:行者123 更新时间:2023-11-30 06:52:40 24 4
gpt4 key购买 nike

我有一个方法(可以被不同的线程同时调用)创建一个异步任务并返回一个CompletableFuture。我想通过将任务与 whenComplete(...) 链接来测量运行任务所需的时间,如下所示:

public CompletableFuture<Result> createTask(...) {
CompletableFuture<Result> result = ...;
final long startTime = System.currentTimeMillis();
result.whenComplete((res, err) -> {
System.out.println(System.currentTimeMillis() - startTime);
}
}

我传入的lambda是异步执行的,我写的方法也是多线程的。这个 lambda 能打印出准确的时间吗?当 lambda 被不同线程异步执行时,Java 如何处理变量作用域?

最佳答案

当 lambda 捕获变量时,您可以将其视为 lambda 获取该变量值的副本。因为只能捕获 final 或有效的 final 变量,所以 lambda 可以安全地复制它们。它们的值不会改变,因此不存在副本与原始变量不同步的危险。

Lambda 不需要使用匿名类来实现,但您可以在概念上将它们视为匿名类的语法糖。你的whenComplete调用相当于:

long startTime = System.currentTimeMillis();

result.whenComplete(new BiConsumer<T, U>() {
@Override public void accept(T res, U err) {
System.out.println(System.currentTimeMillis() - startTime);
}
});

事实是,变量捕获对于 lambdas 来说并不新鲜。匿名类也捕获变量,他们在 lambda 出现之前就这样做了。结果是,他们 secret 地隐藏了捕获变量的副本。他们获得合成的私有(private)字段来存储那些隐藏的值。上面的代码实际上更像这样,如果我们明确合成字段:

long startTime = System.currentTimeMillis();

result.whenComplete(new BiConsumer<T, U>() {
private final long _startTime = startTime;

@Override public void accept(T res, U err) {
System.out.println(System.currentTimeMillis() - _startTime);
}
});

注意一旦这个匿名BiConsumer被实例化它站在自己的两只脚上。 accept()的正文现在指的是一个实例变量,而不是捕获的变量。匿名对象不依赖于外部函数,也不依赖于创建它的线程。 accept()可以随时从任何线程调用,并且会像预期的那样运行,即使原始的 startTime变量早已死亡和埋葬。

关于java - Java 作用域中的异步 lambda 如何处理局部变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38536835/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com