这个答案 指示如何转换 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 }
?在手中创建一个新线程并在那里阻塞,是不是在未来阻止?如果没有,它有什么不同?
两者之间几乎没有区别 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
10秒有点太长了 2+2
评价。
所有其他 future
s和同一执行上下文中的所有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 {...
,但额外的执行上下文允许您限制线程数。
它实际上非常简单。 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
和a new Runnable
要么 new Callable
允许计算执行/独占子线程。
在示例@senia中给出:
new Thread(new Runnable { def run() {
promise.complete(Try{ jfuture.get })
}}).start
这有什么不同 future {jfuture.get}
?它不会阻止您的默认设置 ExecutionContext
由Scala提供,它具有与机器处理器一样多的线程。
这意味着代码中的所有其他期货将始终等待 future { jfuture.get }
完成,因为整个上下文被阻止。