While trying to create a simple test case to reproduce cyclic object initialization problems in Scala, I accidentally created this example and one variant does terminate and the other not, while it only depends on the type of the used thread pool:
import scala.concurrent.Future
import scala.concurrent._
import scala.concurrent.duration._
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 {
// comment in and app does not finish:
// implicit val execContext = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(2))
//Left before: Thread[pool-1-thread-1,5,main]
//Base before: Thread[pool-1-thread-1,5,main]
//Right before: Thread[pool-1-thread-1,5,main]
//Base after: Thread[pool-1-thread-1,5,main]
// comment in and app does finish
//import scala.concurrent.ExecutionContext.Implicits.global
// output:
//Left before: Thread[ForkJoinPool-1-worker-29,5,main]
//Base before: Thread[ForkJoinPool-1-worker-29,5,main]
//Right before: Thread[ForkJoinPool-1-worker-29,5,main]
//Base after: Thread[ForkJoinPool-1-worker-29,5,main]
Await.result(Future(Left.basePath), 1.seconds)
Await.result(Future(Right.basePath), 1.seconds)
}
Why is that?