首页 > 解决方案 > 如何识别/获取循环对象初始化导致Scala死锁的自动提示?

问题描述

由于循环对象初始化,以下代码会遇到未来的超时(在 Scala 2.x 和 Dotty 中,-Xcheckinit 或 -Ycheck-init 在这里没有帮助)。在复杂的项目中,这些周期通常隐藏得很好。是否有可能从编译器或至少在运行时获得帮助?在多线程环境中如何防止这种情况发生?

import scala.concurrent.Future
import scala.concurrent._
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

object Base {
  val LeftElement = "Left"
  val RightElement = "Right"

  println("Base before: " + Thread.currentThread())
  val all = Set(Left, Right)
  println("Base after: " + Thread.currentThread())
}

object Left {
  println("Left before: " + Thread.currentThread())
  val basePath = Base.LeftElement
}

object Right {
  println("Right before: " + Thread.currentThread())
  val basePath = Base.RightElement
}

object Main extends App {
  val f1 = Future(Left)
  val f2 = Future(Right)
  println(Await.result(f1, 1 second))
  println(Await.result(f2, 1 second))
}

标签: multithreadingscaladeadlockobject-initialization

解决方案


通常,编译器和 JVM 不会帮助您避免这种情况。

解决此问题的最佳方法是延迟评估周期,例如:

  • 使用lazy val
  • 使用def

请注意,与简单的val. 我没有做过实验,但我怀疑lazy val(产生一些同步的费用)对于像这样的情况更好

lazy val all = Set(Left, Right)

限制冗余对象的分配,这def对于像这样的情况更好

def basePath = Base.LeftElement

因为这很可能会被 JIT 内联。

另请参阅:如何诊断或检测静态初始化程序中的死锁


推荐阅读