Skip to content

Deadlock with inner object class init #9312

Open
@scabug

Description

@scabug

When the following program is run, the threads end up in a deadlock.

object DeadLockTest {
  def main(args: Array[String]): Unit = {
    def run(block: => Unit): Unit =
      new Thread(new Runnable {def run(): Unit = block}).start()

    run {println(Parent.Child1)}
    run {println(Parent.Child2)}

  }

  object Parent { self =>
    trait Child {
      Thread.sleep(2000) // ensure concurrent behavior
      val parent = self
      def siblings = parent.children - this
    }

    object Child1 extends Child
    object Child2 extends Child

    final val children = Set(Child1, Child2)
  }
}

The deadlock happens because the Child classes are initialized before the Parent. This leads to the following chain of actions:

  • thread 1 starts to init class Child1 (calls the static initializer cinit, which calls the constructor init)
  • thread 2 starts to init class Child2
  • thread 1 starts to init Parent to get a reference to it into the val parent
  • thread 2 tries to get reference to Parent to place it in the val parent, but as the class Parent is being inited by thread 1, it waits
  • thread 1 tries to get reference to Child2 to place it into the val children, but as the Child2 class is being initied by thread2, it waits

For me as a programmer, when looking at the syntax, I would expect Parent.Child1 to mean that we take a reference to Parent, which has a field called Child1 containing the reference to the singleton object Child1. This would ensure that Parent1 is initialized before Child2 can be used. Ofcourse what really happens is that a reference to Parent.Child1 just uses the Parent1.MODULE$ to get the reference without bother Parent at all. Thus to me this is a bug/design failure in how scala handles inner objects.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions