在以下代码片段中:
void method1(String variable1) {
String variable2 = "something";
String variable3 = getValue3();
service.asyncMethod1().thenAcceptAsync(result -> {
service.asyncMethod2(variable1, variable2, variable3).thenAcceptAsync(result2 -> {
log.info("success!");
});
});
}
如何确保调用asyncMethod2时可以正确访问变量variable1、variable2和variable3? 考虑到method1可能会在asyncMethod1之前完成执行,如何确保在thenAcceptAsync中调用asyncMethod2以获取asyncMethod1的结果时这些变量可用?
编辑:异步方法返回 CompletableFuture<>,方法 getValue3() 是一个普通的同步方法
局部变量和参数在 lambda 主体运行时不会被访问。
当您的代码计算 lambda 表达式时,它会返回一个闭包 object,其中包含每个引用的局部变量、方法、构造函数或异常参数的 value 的副本(所有这些都像局部变量一样工作,特别是作为堆栈槽实现);当您随后调用该闭包对象的(单个)方法时——即“运行”lambda——它(如果适用)使用这些复制的值执行或评估 lambda 主体,这些复制的值只要闭包对象存在就存在,甚至如果原始本地和/或参数已被释放,因为声明/分配它们的代码块已完成。
由于对闭包中副本的更新不会影响原始副本,并且对原始副本的更新也不会影响副本,因此 Java 禁止 any 更新。请参阅JLS 15.27.2中的第11段“任何使用但未在 lambda 表达式中声明的局部变量、形式参数或异常参数必须是最终的或有效的最终......”。如果它被声明为最终语言,则该语言将阻止您重新分配它;如果它实际上是最终的,那么您就不会尝试重新分配它。如果您重新分配它,则无法在 lambda-body 中使用它。
这类似于内部类的工作方式 - 如果在实例上下文中是本地或匿名的,它具有对该上下文的外部类对象的引用,因此它可以写入该对象的字段并查看其他地方完成的写入,但它(仅)使用了任何局部变量或参数的副本,这些副本可能会在内部类对象存在时消失。在 Java 的早期版本中,此类引用的局部变量必须声明为最终的; Java 8 将其放宽为“有效最终”,只需不重新分配它就足够了。