由于货币问题,使局部变量为最终变量或有效最终变量的原因。在jls 8规范中,它声明如下。
对有效最终变量的限制禁止访问 动态变化的局部变量,其捕获可能 引入并发问题。
一切都好,但是我做了一些实验。如果我同步该方法,那将消除动态更改局部变量的可能性,因为我保证只有一个线程可以执行此代码。但是编译器抛出错误,指出它必须是最终的或实际上是最终的。
逻辑对吗?
考虑以下代码:
public synchronized void capture() {
int localVariable = 100;
Interf i = (text) -> System.out.println(text + localVariable);
i.m1("This local variable is: ");
localVariable = 1000;
}
}
答案 0 :(得分:0)
答案很简单,您的变量在方法末尾超出了范围。使用有效的最终变量可以轻松解决此问题,因为编译器只需将值复制到lambda中即可。由于lambda表达式中的代码也可以在方法之外运行(其中 modifiable 变量已被垃圾回收),因此此方法不起作用。您也不能指望编译器会以某种方式复制变量,然后在lambda表达式之外对其进行修改时动态地对其进行更改。我希望可以清除它。
答案 1 :(得分:0)
但是编译器抛出错误,指出它必须是最终的或实际上是最终的。
那是因为它按照规则执行。不,不是,而是;不管您是否真正防范了所有并发问题,如果它不是最终的,它就不会编译。
在您的简单示例中,这可能没问题。但是,使方法同步是无关紧要的,因为无论如何局部变量始终将与每个线程的调用相关联。编译器担心的是方法本身上下文中的线程问题,这很容易在使用lambda时发生(将来可能在非最终变量的状态改变后的任意时间执行) ,如果有的话,还不清楚应该使用哪种状态-初始状态还是更新状态。
答案 2 :(得分:0)
想象一下您拥有的lambda创建了一个由CompkJoinPool或其他执行程序执行的CompletableFuture吗?
这就是为什么在此方法上进行同步不足以推翻有效地终止局部变量的规则。 Lambda将同步执行并被同步,但是它创建的异步任务将不会执行。