为什么我的简单scala对象在包含future时会挂起一分钟左右



我正在学习scala期货,我已经找到了我的问题。我有一个非常简单的例子

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util.{Failure, Success}
/**
 * Created by dummy on 05/02/15.
 */
object FutureUtils extends App{
  val f = Future {
    Thread.sleep(1000)
    println("I am learning scala futures")
    "learning"
  }
  f onComplete {
    case Success(value:String) => println("got the response back")
    case Failure(t: Throwable) => println("did not expect this")
  }
  println("I am still learning")
}

当我按原样运行程序时,输出永远不会打印

收到的回复

相反,它看起来会挂起一分钟左右,然后结束,而不打印预期的输出。我确信我错过了一些非常基本的东西。

我还尝试在末尾添加System.in.read(),当我输入任何伪值时,程序似乎会结束打印预期结果。这种行为背后的原因是什么?有人能帮我理解吗?

程序在没有System.in.read()的情况下无法工作的原因是onComplete在未来完成之前不会阻塞,而只是添加了一个回调。这个回调永远不会被执行,因为整个程序在未来完成之前就结束了。要解决这个问题,可以故意让主线程进入无限循环,并在回调中显式终止进程。

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util.{Failure, Success}
object Main extends App {
  val f = Future {
    Thread.sleep(1000)
    println("I am learning scala futures")
    "learning"
  }
  f onComplete {
    case Success(value:String) => println("got the response back"); System.exit(0)
    case Failure(t: Throwable) => println("did not expect this"); System.exit(1)
  }
  println("I am still learning")
  while (true){
    Thread.sleep(1000)
  }
}

您需要等待未来,程序在完成之前已经退出。

import scala.concurrent.Await
import scala.concurrent.duration._
var myFuture = Future {
    Thread.sleep(1000)
    1
}
// oncomplete handlers, etc here
println(Await.result(myFuture, 5 seconds))

EDIT:如果您必须使用onComplete,并且无法验证这些处理程序是否在Await.ready/result之前执行,那么您应该使用正式同步,即:

import scala.concurrent._
import java.util.concurrent.CountDownLatch
object Main extends App {
  val f = Future {
    Main.synchronized {
      Thread.sleep(1000);
      1
    }
  }
  val latch = new CountDownLatch(1)
  f.onComplete {
    case _ => { latch.countDown() }
  }
  latch.await()
}

嗯。。。既然你在未来睡了1000毫秒,那么你的未来至少需要1秒才能完成。应用程序线程完成自身并在此时退出。

你必须确保应用程序线程在未来完成时是活跃的。你可以通过在应用程序线程中睡眠一段时间来做到这一点。。。像这样。

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util.{Failure, Success}
object FutureUtils extends App{
  val f = Future {
    Thread.sleep(1000)
    println("I am learning scala futures")
    "learning"
  }
  f onComplete {
    case Success(value:String) => println("got the response back")
    case Failure(t: Throwable) => println("did not expect this")
  }
  // Wait for some time
  // Not sure future will complete in this time or not
  Thread.sleep(1000);
  Thread.sleep(1000);
  Thread.sleep(1000);
}

但是,更好的方法是让应用程序线程在未来完成。

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent._
import scala.util.{ Failure, Success }
object FutureUtils extends App {
  val f = Future {
    Thread.sleep( 1000 )
    println( "I am learning scala futures" )
    "learning"
  }
  f onComplete {
    case Success( value:String ) => println( "got the response back" )
    case Failure( t: Throwable ) => println( "did not expect this" )
  }
  while ( f.value == None ) {
    // Waste time just till the future is complete.
  }
  // Do something with future value.
  f.foreach( ( s: String ) => println( s ) )
}

最新更新