Jest to nieodłączny problem, który może wystąpić w programie Scala po zwolnieniu odwołania do obiektu singleton przed ukończeniem budowy. Dzieje się tak z powodu innego wątku próbującego uzyskać dostęp do obiektu, zanim zostanie on w pełni skonstruowany. Nie ma to nic wspólnego z metodą main
, a raczej z inicjowaniem obiektu zawierającego metodę main
- spróbuj uruchomić to w REPL, wpisując wyrażenie ParCollectionInInitializerTest
, a otrzymasz te same wyniki. Nie ma też nic wspólnego z wątkami roboczymi łączenia widmowego będącymi wątkami demona.
Obiekty Singleton są inicjowane leniwie. Każdy obiekt singletonowy można zainicjować tylko jeden raz. Oznacza to, że pierwszy wątek, który uzyskuje dostęp do obiektu (w twoim przypadku główny wątek) musi chwycić blokadę obiektu, a następnie zainicjować go. Każdy kolejny wątek, który nadejdzie później, musi poczekać na główny wątek, aby zainicjować obiekt i ostatecznie zwolnić blokadę. W ten sposób obiekty singleton są implementowane w Scali.
W twoim przypadku wątek pracownika pobierania równoległego próbuje uzyskać dostęp do obiektu singleton, aby wywołać doSomething
, ale nie może tego zrobić, dopóki główny wątek nie zakończy inicjowania obiektu - więc czeka. Z drugiej strony wątek główny czeka w konstruktorze, aż operacja równoległa zakończy się, co jest uzależnione od ukończenia wątków roboczych - główny wątek cały czas utrzymuje blokadę inicjalizacji dla singletonu. Dlatego pojawia się impas.
Można spowodować ten problem z kontraktami od 2,10, lub ze zwykłych wątków, jak pokazano poniżej:
def execute(body: =>Unit) {
val t = new Thread() {
override def run() {
body
}
}
t.start()
t.join()
}
object ParCollection {
def doSomething() { println("Doing something") }
execute {
doSomething()
}
}
Wklej to do REPL, a następnie napisać:
scala> ParCollection
i rEPL zawiesza się.
powiązane: http: // stackoverflow.com/questions/27549671/how-to-diagnose-lub-detect-deadlocks-in-java-static-initializers – Rich