21

我将 Play Framework 2.1.1 与一个生成 java.util.concurrent.Future 结果的外部 java 库一起使用。我使用的是 scala 未来而不是 Akka,我认为从 Play 2.1 开始这是正确的做法。如何将 java.util.concurrent.Future 包装到 scala.concurrent.Future 中,同时仍然保持代码非阻塞?

def geConnection() : Connection = {
  // blocking with get
  connectionPool.getConnectionAsync().get(30000, TimeUnit.MILLISECONDS)
}

上面的代码返回一个连接但使用了一个 get 所以它变成阻塞

def getConnectionFuture() : Future[Connection] = {
  future {
    // how to remove blocking get and return a scala future?
    connectionPool.getConnectionAsync().get(30000, TimeUnit.MILLISECONDS)
  }
}

理想情况下,我想要一个 scala 函数,它像上面的代码一样将连接作为未来返回,但没有通过 get 阻塞代码。我还需要在函数中添加什么以使其非阻塞。

任何指针都会很棒。

4

4 回答 4

21
import java.util.concurrent.{Future => JFuture}
import scala.concurrent.{Future => SFuture}

你不能在没有阻塞的情况下进行包装,JFuture因为( )SFuture中有一个回调并且只有.SFutureonCompletegetJFuture

您所能做的就是创建额外的线程并用 阻塞它get,然后Promiseget.

val jfuture: JFuture[T] = ???
val promise = Promise[T]()
new Thread(new Runnable { def run() { promise.complete(Try{ jfuture.get }) }}).start
val future = promise.future

您可以检查isDone无限循环,但我认为这并不比阻塞更好。

于 2013-06-20T14:01:08.640 回答
6
Future {
  blocking {
    jfuture.get
  }
}

这让 ExecutionContext 知道你正在做的事情将被阻塞,让它有机会分配更多的线程。如果你不包括blocking { },那么你可能会用完线程。

于 2016-02-25T19:13:40.997 回答
2
     import java.util.concurrent.{Future => JFuture}
     import scala.concurrent.ExecutionContext.Implicits.global
     import scala.concurrent.Future
     import scala.util.Try

     object JFuture2SFuture {
        val jFuture: JFuture[Int] = ???
        val promise = Promise[Int]()
        Future { promise.complete(Try(jFuture.get)) } //it is non blocking 
        val sFuture:Future[Int] = promise.future

     }
于 2017-12-03T10:03:12.313 回答
-1

scala-java8-compat库提供了 java8 和 Scala Futures 之间的转换器。

具体来说,您可以使用FutureConverters.toScala(connectionPool.getConnectionAsync())java.util.concurrent.Futurescala.concurrent.Future

于 2017-09-09T20:04:30.453 回答