由于并发问题,局部变量成为最终变量或有效最终变量的原因。在 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; }}
3 回答
阿晨1998
TA贡献2037条经验 获得超6个赞
答案很简单,您的变量在方法结束时超出了范围。使用有效的最终变量可以轻松解决这个问题,因为编译器只是将值复制到 lambda 中。由于 lambda 表达式中的代码也可以在方法外部运行(其中可修改变量已被垃圾收集),因此这是行不通的。您也不能指望编译器以某种方式复制您的变量,然后在 lambda 表达式之外修改它时动态更改它。我希望这能解决问题。
慕村225694
TA贡献1880条经验 获得超4个赞
想象一下您创建的 CompletableFuture 由 ForkJoinPool 或其他执行器执行的 lambda?
这就是为什么此方法上的同步不足以推翻局部变量有效为最终的规则。lambda 将同步执行并同步,但它创建的异步任务不会。
婷婷同学_
TA贡献1844条经验 获得超8个赞
但编译抛出了一个错误,指出它必须是最终的或有效的最终的。
那是因为它是按照规则进行的。不,是,没有但是;您是否真正防范了所有并发问题并不重要 - 如果它不是有效的最终版本,它就不会编译。
在您这里的简单示例中,可能没问题。然而,使方法同步是无关紧要的,因为无论如何局部变量总是与它们的每线程调用相关联。编译器担心的是方法本身上下文中的线程问题,并且在使用 lambda 时很容易发生这种情况(在非最终变量的状态可能发生变化之后,可能会在将来的任意时间执行) ,如果有的话,根本不清楚应该使用什么状态 - 初始状态还是更新后的状态。)
添加回答
举报
0/150
提交
取消