31

我正在围绕 java 库编写一个小型 scala 包装器。

Java 库有一个对象 QueryExecutor 公开 2 个方法:

  • 执行(查询):结果
  • asyncExecute(查询):ListenableFuture [结果]

在这种情况下,ListenableFuture 是来自 guava 库的。

我希望我的 scala 包装器返回 Future[Result] 而不是 java 对象,但我不确定实现它的最佳方法是什么。这是我想出的2个解决方案:

future {
  executor.execute(query)
}

val p = promise[Result]
val guavaFuture = executor.asyncExecute(query)

Futures.addCallback(guavaFuture, new FutureCallback[Result] {
  def onFailure(t: Throwable) {
    p.failure(t)
  }

  def onSuccess(result: Result) {
    p.success(result)
  }
})

p.future

我想知道哪种方法最好。我的直觉是,第一个在返回 Future 时仍然会阻塞一个线程,而执行调用等待响应,第二个看起来应该是非阻塞的。对每种方法的优缺点有何评论?

4

2 回答 2

47

第二种选择是最好的,它使一切保持异步。但是...您可以做得更好,并将解决方案抽象为可重用的模式:

implicit class RichListenableFuture[T](lf: ListenableFuture[T]) {
  def asScala: Future[T] = {
    val p = Promise[T]()
    Futures.addCallback(lf, new FutureCallback[T] {
      def onFailure(t: Throwable): Unit = p failure t
      def onSuccess(result: T): Unit    = p success result
    })
    p.future
  }    
}

然后,您可以简单地调用:

executor.asyncExecute(query).asScala
于 2013-10-22T21:23:45.607 回答
3

另一个稍短的解决方案:

implicit class ListenableFutureDecorator[T](val f: ListenableFuture[T]) extends AnyVal {
  def asScala(implicit e: Executor): Future[T] = {
    val p = Promise[T]()
    f.addListener(() => p.complete(Try(f.get())), e)
    p.future
  }
}
于 2018-09-24T07:23:35.687 回答