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.
When the following program is run, the threads end up in a deadlock.
The deadlock happens because the Child classes are initialized before the Parent. This leads to the following chain of actions:
cinit, which calls the constructorinit)val parentval parent, but as the class Parent is being inited by thread 1, it waitsval children, but as the Child2 class is being initied by thread2, it waitsFor me as a programmer, when looking at the syntax, I would expect
Parent.Child1to mean that we take a reference toParent, which has a field calledChild1containing the reference to the singleton objectChild1. This would ensure that Parent1 is initialized before Child2 can be used. Ofcourse what really happens is that a reference toParent.Child1just uses theParent1.MODULE$to get the reference without botherParentat all. Thus to me this is a bug/design failure in how scala handles inner objects.