Java 为什么是新线程而不是未来{…}
指示如何将Java 为什么是新线程而不是未来{…},java,multithreading,scala,blocking,future,Java,Multithreading,Scala,Blocking,Future,指示如何将java.util.concurrent.Future转换为scala.concurrent.Future,同时管理阻塞发生的位置: import java.util.concurrent.{Future=>JFuture} 导入scala.concurrent.{Future=>SFuture} val jfuture:jfuture[T]=??? val promise=promise[T]() 新线程( 新Runnable{ def run(){promise.complete(
java.util.concurrent.Future
转换为scala.concurrent.Future
,同时管理阻塞发生的位置:
import java.util.concurrent.{Future=>JFuture}
导入scala.concurrent.{Future=>SFuture}
val jfuture:jfuture[T]=???
val promise=promise[T]()
新线程(
新Runnable{
def run(){promise.complete(尝试{jfuture.get})}
}
).开始
val future=promise.future
我的问题与评论中提出的问题相同:
future{jfuture.get}
有什么问题吗?为什么你用了一个额外的线程结合承诺
答复如下:
它会在你的拉线过程中挡住线。如果您已经为这种未来配置了ExecutionContext,则可以,但默认ExecutionContext包含的线程数量与处理器数量相同
我不确定我是否理解这个解释。重申:
future{jfuture.get}
有什么问题吗?在未来内部阻塞与手动创建新线程并在那里阻塞不一样吗?如果没有,又有什么不同呢?其实很简单scala.concurrent.Promise
是未来
的具体实现,注定是异步计算
当您想要转换时,使用jfuture.get
,您正在运行一个阻塞计算并输出一个立即解析的scala.concurrent.Future
线程将阻塞,直到jfuture
中的计算完成。get
方法被阻塞
阻塞意味着在计算完成之前,线程内不会发生任何其他事情。在间歇检查结果时,您实际上是在用类似于的东西垄断线程
while (!isDone() && !timeout) {
// check if the computation is complete
}
具体而言:
val jfuture: JFuture[T] = ??? // some blocking task
当无法避免阻塞时,通常的做法是生成新线程
和新可运行线程
或新可调用线程
,以允许计算执行/独占子线程
在@senia给出的示例中:
new Thread(new Runnable { def run() {
promise.complete(Try{ jfuture.get })
}}).start
这与future{jfuture.get}
有何不同?它不会阻止Scala提供的默认ExecutionContext
,Scala的线程数与机器处理器的线程数相同
这意味着代码中的所有其他未来都必须等待future{jfuture.get}
完成,因为整个上下文都被阻止。future{jfuture.get}
和future{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
默认线程池中的线程数量与处理器数量相同
使用jfuture.get
将阻塞1个线程
假设您有8个处理器。另外,我们假设每个jfuture.get
需要10秒。现在创建8future{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和所有参与者将停止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
您可以使用new Thread(new Runnable{…
)实现blockingFuture
,但是额外的执行上下文允许您限制线程数。您到底不明白什么?线程阻塞意味着什么?@AlexeiKaigorodov我稍微修改了我的问题:future{jfuture.get}
?在未来内部阻止与手动创建新线程并在那里阻止不一样吗?如果不一样,有什么区别?是的,在未来内部阻止与手动创建新线程并在那里阻止一样糟糕。转换为scala.concurrent.future
的想法是通过使用onComplete
来避免完全阻止我的印象是,生成一个新线程并在其中执行somethingtatblocks()
与将来(somethingtatblocks())是一样的。我的问题主要是关于这是否是真的,如果不是,又有什么不同?因此,一般来说,不建议在具有默认执行上下文的将来进行长时间的计算?@DominykasMostauskis:不,默认执行上下文有一个线程池,并选择其中一个线程池在将来运行代码。它不跨新线程因为创建线程是一个昂贵的操作,线程是一个有限的资源。没有内在的原因,计算2+2的未来需要在其他未来之后执行。(您只要求异步计算9件事情。)如果您更改future{thread.sleep(10000)}
toFuture{blocking{Thread.sleep(10000)}
,2+2未来将立即执行。我的理解是,阻塞
方法给出了一个提示,线程池将首先处理其他未来。我还没有找到任何好的资源来准确描述这里发生了什么。@Patrick这是真的。当使用阻塞
时,全局线程池将为该计算创建一个新线程,这样它就不会耗尽线程。更多信息请参见“阻塞”部分