【问题标题】:Scala futures and JMMScala 期货和 JMM
【发布时间】:2019-03-23 01:34:10
【问题描述】:

我有一个关于 JMM 和 Scala 期货的问题。

在下面的代码中,我有非不可变的 Data 类。我在一个线程内(在 Future 应用主体内)创建它的一个实例,然后订阅完成事件。

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

object Hello extends App {
  Future {
    new Data(1, "2")
  }.foreach { d =>
    println(d)
  }
  Thread.sleep(100000)
}

class Data(var someInt: Int, var someString: String)

我们能否保证:

  1. foreach 主体从创建 Data 实例的同一线程调用?
  2. 如果不是,我们能否保证 Future.apply happens-before(就 JMM 而言)foreach 正文中的操作?

【问题讨论】:

  • Scala 规范是否声明 JMM 适用于 Scala 程序?
  • Holger,JMM 适用于任何运行在 JVM 上的应用程序
  • 不,JMM 是 Java Language 规范的一部分。 JVM 必须符合它自己的规范,并且可以公平地假设,给定一个正确编译的 Java 应用程序,它在 JVM 上的执行将符合 JMM。但是,当我们不知道生成的字节码时,这并没有说明具有不同、未知语言结构甚至类似结构的任意编程语言。实际上,您的问题就是一个例子。只有 Scala 的规范才能回答这个问题。它必须指定的第一件事是 JMM 是否适用于它(以及如何适用)。

标签: scala concurrency jvm thread-safety future


【解决方案1】:

完成happens-before回调执行。

免责声明:我是主要贡献者。

【讨论】:

    【解决方案2】:

    我有一个类似的问题,我发现是 -

    1) 在 Intellij 文档中很方便地为我拉了出来,上面写着

    一旦值变得可用,就在未来异步处理该值...

    2) 在https://docs.scala-lang.org/overviews/core/futures.html 上面写着

    一旦未来完成,结果就可用。

    基本上,我能找到的任何地方都没有明确说存在内存障碍。但是,我怀疑,这是一个安全的假设。否则该语言将无法正常工作。

    【讨论】:

      【解决方案3】:

      您可以通过查看Promise/DefaultPromise/Future 的源代码来了解这一点,它会在执行上下文中安排foreach 的回调/将其添加到侦听器中而不需要任何要求它在原始线程上运行的特殊逻辑...

      但您也可以通过实验验证它,方法是尝试设置执行上下文和线程,以便在创建 DataFuture 完成时,其他内容已经排队等待执行。

      implicit val context = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(2))
      
      Future {
        new Data(1, "2")
        println("Data created on: " + Thread.currentThread().getName)
        Thread.sleep(100)
      }.foreach { _ =>
        println("Data completed on: " + Thread.currentThread().getName)
      }
      
      Future { // occupies second thread
        Thread.sleep(1000)
      }
      
      Future { // queue for execution while first future is still executing
        Thread.sleep(2000)
      }
      

      我的输出:

      数据创建于:pool-$n-thread-1

      数据完成于:pool-$n-thread-2

      2.

      这里没有我想的那么自信,但我会试一试:

      是的。

      DefaultPromiseFuture 的底层结构,正在包装一个原子引用,其行为类似于一个 volatile 变量。由于更新结果的写入必须发生在将结果传递给侦听器的读取之前,以便它可以运行回调,因此 JMM 易失变量规则将其转换为 happens-before 关系。

      【讨论】:

        【解决方案4】:
        1. 我认为不能保证从同一个线程调用 foreach
        2. 在future 成功完成之前不会调用foreach。 onComplete 是一种更惯用的方式,它提供回调来处理 Future 的结果。

        【讨论】:

        • 你错过了第二个问题的重点。我知道将来完成时会调用 foreach 。我的问题是关于 JMM 方面这两个动作之间的关系
        猜你喜欢
        • 1970-01-01
        • 2013-04-27
        • 2015-07-22
        • 2021-03-02
        • 1970-01-01
        • 2015-04-19
        • 2017-11-18
        • 2015-07-09
        • 2013-12-16
        相关资源
        最近更新 更多