为什么新线程而不是未来{...}

Dom*_*kis 11 java multithreading scala future blocking

此答案指示如何转换java.util.concurrent.Futurescala.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
Run Code Online (Sandbox Code Playgroud)

我的问题与评论中提出的问题相同:

怎么了future { jfuture.get }?为什么你使用额外的线程与Promise结合?

答案如下:

它会在你的线程拉动中阻止线程.如果您为这样的期货配置了ExecutionContext,那很好,但是默认的ExecutionContext包含与处理器一样多的线程.

我不确定我理解这个解释.重申:

怎么了future { jfuture.get }?在手中创建一个新线程并在那里阻塞时,在未来内部是否阻塞?如果没有,它有什么不同?

sen*_*nia 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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

您可以实现blockingFuture使用new Thread(new Runnable {...,但是额外的执行上下文允许您限制线程数.


fla*_*ian 7

它实际上非常简单.scala.concurrent.Promise是a的具体实现Future,注定是异步计算.

当你想转换时jfuture.get,你正在运行一个阻塞计算并输出一个立即解决的scala.concurrent.Future.

Thread将阻塞,直到计算内jfuture完成.该get方法是阻止的.

阻塞意味着Thread在计算完成之前不会发生任何其他事情.你本质上是垄断了Thread一个看起来像是一个while间歇性检查结果的循环的东西.

while (!isDone() && !timeout) {
   // check if the computation is complete
}
Run Code Online (Sandbox Code Playgroud)

特别:

val jfuture: JFuture[T] = ??? // some blocking task
Run Code Online (Sandbox Code Playgroud)

当无法避免阻塞时,通常的做法是生成a new Thread和a new Runnablenew Callable允许计算执行/独占子线程.

在示例中@senia给出:

new Thread(new Runnable { def run() {
  promise.complete(Try{ jfuture.get })
}}).start
Run Code Online (Sandbox Code Playgroud)

这有future {jfuture.get}什么不同?它不会阻止ExecutionContextScala提供的默认设置,它具有与计算机处理器一样多的线程.

这意味着代码中的所有其他期货将始终必须等待future { jfuture.get }完成,因为整个上下文都被阻止.