1

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?

Mario Galic
  • 47,285
  • 6
  • 56
  • 98
Chris W.
  • 2,266
  • 20
  • 40
  • I can't reproduce. – Levi Ramsey Jul 28 '20 at 16:38
  • Note that the number of threads in `scala.concurrent.ExecutionContext.global` (and its `implicit` version in `s.c.ExecutionContext.Implicits`) depends on the number of cores detected by the JVM, which will vary from machine to machine, container invocation to container invocation, and (in a container) JVM version to JVM version. It's kind of the enemy of reproducibility :) – Levi Ramsey Jul 28 '20 at 16:54
  • (for me, the futures complete with a size-2 fixed thread pool EC). – Levi Ramsey Jul 28 '20 at 16:54
  • Possibly related to `global` having daemonic threads whilst `newFixedThreadPool` creates non-daemonic threads https://stackoverflow.com/a/62884873/5205022 – Mario Galic Jul 28 '20 at 22:51
  • Cheers for the hints! It's the daemonic threads for sure! BTW. here is the problem (in a correct way) leading me to this. https://stackoverflow.com/questions/63149269/how-to-identify-get-automated-hints-with-cyclic-object-initialization-causing – Chris W. Jul 29 '20 at 08:19

0 Answers0