This answer指示如何将java.util.concurrent.Future
转换为scala.concurrent.Future
,同时管理阻止发生的位置:
import java.util.concurrent.{Future => JFuture}
import scala.concurrent.{Future => SFuture}
val jfuture: JFuture[T] = ???
val promise = Promise[T]()
new Thread(
new Runnable {
def run() { promise.complete(Try{ jfuture.get }) }
}
).start
val future = promise.future
我的问题与评论中提出的问题相同:
future { jfuture.get }
出了什么问题?为什么你使用额外的线程与Promise结合?
回答如下:
它会阻止线程拉动中的线程。如果您为这样的期货配置了ExecutionContext,那很好,但默认的ExecutionContext包含与处理器一样多的线程。
我不确定我理解这个解释。重申:
future { jfuture.get }
出了什么问题?在手中创建一个新线程并在那里阻塞时,在未来内部是否阻塞?如果没有,它有什么不同?
答案 0 :(得分:8)
future { jfuture.get }
和future { future { jfuture.get }}
之间几乎没有区别。
默认线程池中存在的脚数与处理器数量一样多。
使用jfuture.get
,您将获得1个线程阻止。
假设您有8个处理器。我们假设每个jfuture.get
需要10秒钟。现在创建8 future { jfuture.get }
。
val format = new java.text.SimpleDateFormat("HH:mm:ss").format(_: Date)
val startTime = new Date
(1 to 8) map {_ => future{ Thread.sleep(10000) }}
future{
2+2
println(s"2+2 done. Start time: ${format(startTime)}, end time: ${format(new Date)}")
}
// 2+2 done. Start time: 20:48:18, end time: 20:48:28
对于2+2
评估,10秒有点太长了。
同一执行上下文中的所有其他future
和所有actor将被停止10秒。
使用额外的执行上下文:
object BlockingExecution {
val executor = ExecutionContext.fromExecutor(new ForkJoinPool(20))
}
def blockingFuture[T](f: => T) = {
future( f )(BlockingExecution.executor)
}
val startTime = new Date
(1 to 8) map {_ => blockingFuture{ Thread.sleep(10000) }}
future{
2+2
println(s"2+2 done. Start time: ${format(startTime)}, end time: ${format(new Date)}")
}
// 2+2 done. Start time: 21:26:18, end time: 21:26:18
您可以使用blockingFuture
实现new Thread(new Runnable {...
,但是额外的执行上下文允许您限制线程数。
答案 1 :(得分:7)
实际上非常简单。 scala.concurrent.Promise
是Future
的具体实现,注定是异步计算。
当您想要使用jfuture.get
转换时,您正在运行阻止计算并输出立即解析的scala.concurrent.Future
。
Thread
将阻止,直到jfuture
内的计算完成。 get
方法正在阻止。
阻止意味着在Thread
之内不会发生任何其他事情,直到计算完成。你实际上是在用Thread
循环查看结果的while
循环来独占while (!isDone() && !timeout) {
// check if the computation is complete
}
。
val jfuture: JFuture[T] = ??? // some blocking task
具体做法是:
new Thread
当无法避免阻塞时,通常的做法是生成new Runnable
和new Callable
或new Thread(new Runnable { def run() {
promise.complete(Try{ jfuture.get })
}}).start
以允许计算执行/独占子线程。
在示例中@senia给出:
future {jfuture.get}
这与ExecutionContext
有什么不同?它不会阻止由Scala提供的默认future { jfuture.get }
,它具有与计算机处理器一样多的线程。
这意味着代码中的所有其他期货将始终等待{{1}}完成,因为整个上下文都被阻止。