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

时间:2014-01-17 15:52:59

标签: java multithreading scala blocking future

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 }出了什么问题?在手中创建一个新线程并在那里阻塞时,在未来内部是否阻塞?如果没有,它有什么不同?

2 个答案:

答案 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.PromiseFuture的具体实现,注定是异步计算。

当您想要使用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 Runnablenew Callablenew Thread(new Runnable { def run() { promise.complete(Try{ jfuture.get }) }}).start 以允许计算执行/独占子线程。

在示例中@senia给出:

future {jfuture.get}

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

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