Короткий ответ
ExecutionContext.Implicits.global
создает демон темы. (см. исходный код Scala scala.concurrent.impl.ExecutionContextImpl.DefaultThreadFactory
) Это потоки, которые JVM не будет ждать при выходе (в вашем случае, когда основная процедура останавливается). Таким образом, до завершения userNameFuture
, который работает как поток демона, основная процедура уже завершена и не ждет для будущих потоков.
Чтобы предотвратить это, используйте либо не-демонный поток, например. создать такой неявный ExecutionContext
implicit val ec = (scala.concurrent.ExecutionContext.fromExecutorService(Executors.newCachedThreadPool()))
или использовать
Await.result(userNameFuture, Duration.Inf)
в основной программе.
Внимание: Если вы используете последний подход с какAwait.result
иonSuccess
обратного вызова, он все еще может случиться, что основные рутинные выходы первого и не выход пользователя будет, поскольку нет никакого порядка, какой из оба делаются первыми.
Длинный ответ
Посмотрите на код
object F2 {
def main(args: Array[String]): Unit = {
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.Success
val userFuture = Future {
Thread.sleep(1000)
println("userFuture runs on: " + Thread.currentThread().getName)
Thread.sleep(1000)
User("Me")
}
val userNameFuture: Future[String] = userFuture map {
user => {
Thread.sleep(2000)
println("map runs on: " + Thread.currentThread().getName)
Thread.sleep(2000)
user.name
}
}
val p = Promise[Boolean]()
userNameFuture onSuccess {
case userName => {
println("onSuccess runs on : " + Thread.currentThread().getName)
println(s"user's name = $userName")
p.complete(Success(true))
}
}
println("main runs on: " + Thread.currentThread().getName)
println("main is waiting (for promise to complete) .... ")
Await.result(p.future, Duration.Inf)
println("main got promise fulfilled")
println("main end ")
}
}
выход которого
main runs on: run-main-b
main is waiting (for promise to complete) ....
userFuture runs on: ForkJoinPool-1-worker-5
map runs on: ForkJoinPool-1-worker-5
onSuccess runs on : ForkJoinPool-1-worker-5
user's name = Me
main got promise fulfilled
main end
Во-первых, вы можете увидеть, что оба userFuture и это карта операция запуска на ForkJoinPool
, как потоки демона.
Во-вторых, сначала выполняется основная работа, печать «main ждет обещания» и ждет здесь (только для целей демонстрации) для выполнения обещания. Если основной не стал бы ждать здесь (попробуйте сами, комментируя Await
) для завершения обещания, основная процедура просто напечатает две другие строки и будет выполнена.В результате, виртуальная машина будет закрыть (и вы никогда не увидите выход onComplete
)
Trick (для отладки) с помощью SBT
В общем, если вы используете SBT и вызвать выполнение программы с помощью run
, то вам все еще может видеть вывод потоков демона, поскольку JVM не завершается, если он запущен из SBT. Итак, если вы начнете с SBT run
, вы скоро вернетесь к приглашению SBT (потому что основная процедура закончилась), но выход SBT (onComplete
) отображается в SBT.
http://stackoverflow.com/questions/31900681/the-future-is-not-complete –
Если вы удалите 'приложение', оно работает так, как ожидалось. – Jus12