确保异步方法链中的变量可访问性

问题描述 投票:0回答:1

在以下代码片段中:

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() 是一个普通的同步方法

java spring asynchronous
1个回答
0
投票

局部变量和参数在 lambda 主体运行时不会被访问。

当您的代码计算 lambda 表达式时,它会返回一个闭包 object,其中包含每个引用的局部变量、方法、构造函数或异常参数的 value 的副本(所有这些都像局部变量一样工作,特别是作为堆栈槽实现);当您随后调用该闭包对象的(单个)方法时——即“运行”lambda——它(如果适用)使用这些复制的值执行或评估 lambda 主体,这些复制的值只要闭包对象存在就存在,甚至如果原始本地和/或参数已被释放,因为声明/分配它们的代码块已完成。

由于对闭包中副本的更新不会影响原始副本,并且对原始副本的更新也不会影响副本,因此 Java 禁止 any 更新。请参阅JLS 15.27.2中的第11段“任何使用但未在 lambda 表达式中声明的局部变量、形式参数或异常参数必须是最终的或有效的最终......”。如果它被声明为最终语言,则该语言将阻止您重新分配它;如果它实际上是最终的,那么您就不会尝试重新分配它。如果您重新分配它,则无法在 lambda-body 中使用它。

这类似于内部类的工作方式 - 如果在实例上下文中是本地或匿名的,它具有对该上下文的外部类对象的引用,因此它可以写入该对象的字段并查看其他地方完成的写入,但它(仅)使用了任何局部变量或参数的副本,这些副本可能会在内部类对象存在时消失。在 Java 的早期版本中,此类引用的局部变量必须声明为最终的; Java 8 将其放宽为“有效最终”,只需不重新分配它就足够了。

© www.soinside.com 2019 - 2024. All rights reserved.