Open
Description
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 constructorinit
) - 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
Labels
No labels