java - 为什么实例字段不需要是 final 或有效 final 才能在 lambda 表达式中使用?

标签 java lambda instance-variables local-variables

我正在用 Java 练习 lambda 表达式。根据 Java SE 16 Lambda Body 的 Oracle 文档,我知道局部变量需要是 final 或有效 final 的:

Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression must either be final or effectively final (§4.12.4), as specified in §6.5.6.1.


但它没有说为什么。搜索我发现了这个类似的问题 Why do variables in lambdas have to be final or effectively final? ,其中 StackOverflow 用户“snr”回复了下一个引用:

Local variables in Java have until now been immune to race conditions and visibility problems because they are accessible only to the thread executing the method in which they are declared. But a lambda can be passed from the thread that created it to a different thread, and that immunity would therefore be lost if the lambda, evaluated by the second thread, were given the ability to mutate local variables.


  • 来源:Why the restriction on local variable capture?

  • 这就是我的理解:一个方法一次只能由一个线程(比如说 thread_1)执行。这确保该特定方法的局部变量仅由 thread_1 修改。另一方面,可以将 lambda 传递给不同的线程 (thread_2),因此...如果 thread_1 完成 lambda 表达式并继续执行方法的其余部分,则它可能会更改局部变量的值,并且,在同时,thread_2 可能会更改 lambda 表达式中的相同变量。然后,这就是存在此限制的原因(局部变量需要是 final 或有效 final 的)。
    对不起,很长的解释。我做对了吗?
    但接下来的问题是:
  • 为什么这种情况不适用于实例变量?
  • 如果 thread_1 与 thread_2 同时更改实例变量会发生什么情况(即使它们没有执行 lambda 表达式)?
  • 实例变量是否以另一种方式保护?

  • 我对Java没有太多经验。对不起,如果我的问题有明显的答案。

    最佳答案

    实例变量存储在堆空间中,而局部变量存储在堆栈空间中。每个线程维护自己的堆栈,因此局部变量不会在线程之间共享。另一方面,堆空间由所有线程共享,因此多个线程可以修改实例变量。有多种机制可以使数据线程安全,您可以在该平台上找到许多相关讨论。为了完整起见,我在下面引用了 http://web.mit.edu/6.005/www/fa14/classes/18-thread-safety/ 的摘录

    There are basically four ways to make variable access safe in shared-memory concurrency:

    • Confinement. Don’t share the variable between threads. This idea is called confinement, and we’ll explore it today.
    • Immutability. Make the shared data immutable. We’ve talked a lot about immutability already, but there are some additional constraints for concurrent programming that we’ll talk about in this reading.
    • Threadsafe data type. Encapsulate the shared data in an existing threadsafe data type that does the coordination for you. We’ll talk about that today.
    • Synchronization. Use synchronization to keep the threads from accessing the variable at the same time. Synchronization is what you need to build your own threadsafe data type.

    关于java - 为什么实例字段不需要是 final 或有效 final 才能在 lambda 表达式中使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67065119/

    相关文章:

    Java : Convert Object consisting enum to Json Object

    recursion - The Little Schemer Evens-only*&co

    java - 我应该使用 java.util.Random 的全局实例,还是每次使用它时都构造一个?

    python - 在 SQLite3 更新中使用实例变量?

    java - 在 Spring Boot MVC 单元测试中无法获取 HAL 格式

    java - 我无法弄清楚我的 NullPointerException 有什么问题,或者它为什么存在

    java - 是否可以在 Apache Spark 中创建嵌套 RDD?

    Lambda 包括对 node_modules 的依赖

    c# - 为什么这个异步 lambda 函数调用不能在 C# 中编译?

    objective-c - 何时使用实例变量,何时使用属性