同步和scala期货的死锁

时间:2016-09-22 21:24:46

标签: scala asynchronous

我似乎无法弄清楚为什么以下代码死锁:

"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))
  }

1 个答案:

答案 0 :(得分:6)

默认池中的最大线程数等于您拥有的核心数。说,8。这就是发生的事情。

第一个线程进入临界区并开始休眠(占用另一个线程)。另外六个线程启动并在同步块的入口处堆积。 (还有三个要启动的调用,但目前没有线程可用,所以他们正在等待。)

睡眠线程唤醒,满足未来,第一个线程退出同步块并完成。这两个线程被返回到池中,因此立即启动另外两个未来。

等待锁定的其中一个线程唤醒并进入关键部分。

现在,池中没有可用的线程:7个线程在等待锁定,一个在临界区内,总共8个。

活动线程尝试提交将要休眠但将被阻止的Future,因为池中没有更多线程可用。

现在,7个线程等待释放锁定,持有锁定的线程正在等待另一个线程变为可用。

- >死锁。

更新 忘记提及:解决问题的方法是将blocking置于processInFuture电话周围。这将让池意识到它需要超越线程的限制。