Скала фьючерсы и JMM - PullRequest
       48

Скала фьючерсы и JMM

0 голосов
/ 18 октября 2018

У меня вопрос по фьючерсам JMM и Scala.

В следующем коде у меня есть неизменяемый класс данных .Я создаю его экземпляр внутри одного потока (внутри тела применения 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 тело, вызванное из того же потока, где был создан экземпляр данных?
  2. Если нет, можем ли мы гарантировать, что действия внутри Future.apply произойдут до (в терминах JMM) действия внутри foreach тела?

Ответы [ 4 ]

0 голосов
/ 06 июля 2019

Завершение happens-before выполнение обратного вызова.

Отказ от ответственности: я основной участник.

0 голосов
/ 03 июля 2019

У меня был похожий вопрос, и я обнаружил, что -

1) в документе Intellij, так удобно для меня, что он говорит:

Асинхронно обрабатываетзначение в будущем, как только оно станет доступным ...

2) на https://docs.scala -lang.org / Overviews / core / futures.html там написано

Результат становится доступным после завершения будущего.

По сути, я нигде не могу сказать, что существует явный барьер памяти.Я подозреваю, однако, что это безопасное предположение.В противном случае язык просто не будет работать.

0 голосов
/ 03 июля 2019
  1. Нет .

Вы можете получить хорошее представление об этом, просмотрев исходный код для Promise / DefaultPromise / Future,который планирует обратный вызов для foreach в контексте выполнения / добавляет его к слушателям без какой-либо специальной логики, требующей его запуска в исходном потоке ...

Но вы также можете проверить это экспериментально, попытавшисьустановите контекст выполнения и потоки так, чтобы что-то еще уже было поставлено в очередь на выполнение после завершения Future, в котором был создан Data.

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.

Меньшеуверен в себе, чем хотелось бы, но я сделаю это:

Да.

DefaultPromise, конструкция, лежащая в основе Future,оборачивает атомарную ссылку, которая ведет себя как переменная переменная.Поскольку запись для обновления результата должна происходить до чтения, из которого результат передается слушателю, чтобы он мог выполнить обратный вызов, правила изменяемой переменной JMM превращают это в отношение happens-before.

0 голосов
/ 18 октября 2018
  1. Я не думаю, что есть какие-либо гарантии, что foreach вызывается из того же потока
  2. foreach не будет вызываться, пока будущее не завершится успешно.onComplete - более идиоматичный способ обеспечения обратного вызова для обработки результата Future.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...