Когда будущее создается, оно обычно начинается сразу, используя один поток. Если в текущем контексте выполнения нет доступных потоков, то он может не начать ваше будущее сразу, а скорее подождать, пока поток не будет освобожден.
В случае, если в вашем контексте выполнения доступен только один поток, может произойти, что выполнение следующего будущего будет ждать окончания предыдущего будущего до sh.
Обычно, у контекста выполнения будет больше доступных потоков (например, в глобальном контексте выполнения scala число потоков по умолчанию равно числу доступных потоков).
В вашем случае проблема может заключаться в том, что завершение Ваше первое будущее может быть настолько быстрым, что оно заканчивается до начала второго.
Вы можете уменьшить его, введя небольшую задержку после печати значения, например, добавив Thread.sleep(10)
после println(s"checking donut stock $donut")
.
После этого изменения ваше будущее будет выполняться медленнее. Это может вызвать другое проблема в том, что поскольку фьючерсы запускаются в потоках демонов, может случиться так, что основной поток завершится до окончания выполнения фьючерсов. В этом случае они будут прерваны перед вызовом onComplete
обратного вызова.
Во избежание этого вы можете дождаться обоих фьючерсов, используя Await
, например:
import scala.concurrent._
import scala.concurrent.duration._
val f1 = donutStock("My Donut").onComplete{
case Success(value) ⇒ println("Call 1 Completed")
case Failure(exception) ⇒ println("Call 1 Failed")
}
val f2 = donutStock("Your Donut").onComplete{
case Success(value) ⇒ println("Call 2 Completed")
case Failure(exception) ⇒ println("Call 2 Failed")
}
val result1 = Await.result(f1, 1 second)
val result2 = Await.result(f2, 1 second)
Если мы можем подождать на будущее, каков вариант использования для onComplete
обратного вызова? Например, это может быть полезно, когда мы определяем функцию, возвращающую Future, и мы не хотим блокировать ее, используя Await
, но мы все еще хотим выполнить какое-то действие, когда будущее завершено.
Например, Вы можете изменить donutStock
, как показано ниже:
def donutStock(donut: String, idx: Int): Future[Int] = {
val f = Future {
(1 until 100).foreach { value ⇒
println(s"checking donut stock $donut")
}
10
}
//we don't block future, but onComplete callback will be still executed when future ends
f.onComplete{
case Success(value) ⇒ println(s"Call $idx Completed")
case Failure(exception) ⇒ println(s"Call $idx Failed")
}
f
}