我似乎无法弄清楚为什么以下代码死锁:
"Locks around blocking futures" should "be re-entrant" in {
val lock = new Object()
def processInFuture = {
lock.synchronized {
// simulate async call made blocking
Await.result(Future {
blocking {
logger.info("Sleeping")
Thread.sleep(100)
logger.info("Waking")
}
}, Duration.Inf)
}
}
// fire off 10 async events and wait on each one
(0 until 10).
map(_ => Future { processInFuture }).
foreach(future => Await.result(future, Duration.Inf))
}
我无法理解为什么在关键部分中使异步同步会导致整个fork-join池出现问题。
如果我使未来在fork连接池的单独池上执行,那么它可以工作。我不明白为什么fork join pool线程不阻塞其他线程然后先完成?是因为游泳池以某种方式被封锁了吗?
我意识到如果它的异步,它总是最好使所有异步,但有些情况不允许(例如带有番石榴缓存的缓存容量)
- 编辑
为了说明@Dima的答案,这是有效的
"Locks around blocking futures" should "be re-entrant" in {
val lock = new Object()
def processInFuture = {
blocking {
lock.synchronized {
// simulate async call made blocking
Await.result(Future {
blocking {
logger.info("Sleeping")
Thread.sleep(100)
logger.info("Waking")
}
}, Duration.Inf)
}
}
}
// fire off 10 async events and wait on each one
(0 until 10).
map(_ => Future { processInFuture }).
foreach(future => Await.result(future, Duration.Inf))
}
答案 0 :(得分:6)
默认池中的最大线程数等于您拥有的核心数。说,8。这就是发生的事情。
第一个线程进入临界区并开始休眠(占用另一个线程)。另外六个线程启动并在同步块的入口处堆积。 (还有三个要启动的调用,但目前没有线程可用,所以他们正在等待。)
睡眠线程唤醒,满足未来,第一个线程退出同步块并完成。这两个线程被返回到池中,因此立即启动另外两个未来。
等待锁定的其中一个线程唤醒并进入关键部分。
现在,池中没有可用的线程:7个线程在等待锁定,一个在临界区内,总共8个。
活动线程尝试提交将要休眠但将被阻止的Future,因为池中没有更多线程可用。
现在,7个线程等待释放锁定,持有锁定的线程正在等待另一个线程变为可用。
- >死锁。
更新 忘记提及:解决问题的方法是将blocking
置于processInFuture
电话周围。这将让池意识到它需要超越线程的限制。