これは、構築が完了する前にシングルトンオブジェクトへの参照を解放するときにScalaで発生する可能性のある固有の問題です。ParCollectionInInitializerTest
これは、オブジェクトが完全に構築される前に、別のスレッドがオブジェクトにアクセスしようとしたために発生します。これはメソッドとは関係ありませんmain
。むしろ、メソッドを含むオブジェクトを初期化することと関係があります。main
これをREPLで実行し、式ParCollectionInInitializerTest
を入力すると、同じ結果が得られます。また、デーモンスレッドであるフォークジョインワーカースレッドとは何の関係もありません。
シングルトンオブジェクトは遅延して初期化されます。すべてのシングルトンオブジェクトは一度だけ初期化できます。つまり、オブジェクトにアクセスする最初のスレッド(この場合はメインスレッド)は、オブジェクトのロックを取得してから初期化する必要があります。その後に来る他のすべてのスレッドは、メインスレッドがオブジェクトを初期化し、最終的にロックを解放するのを待つ必要があります。これは、シングルトンオブジェクトがScalaで実装される方法です。
あなたの場合、並列コレクションワーカースレッドはシングルトンオブジェクトにアクセスして呼び出すことを試みますdoSomething
が、メインスレッドがオブジェクトの初期化を完了するまでそうすることはできません-したがって、待機します。一方、メインスレッドは、すべてのワーカースレッドが完了することを条件として、並列操作が完了するまでコンストラクターで待機します。メインスレッドは、シングルトンの初期化ロックを常に保持します。したがって、デッドロックが発生します。
以下に示すように、2.10からの先物、または単なるスレッドでこの動作を引き起こす可能性があります。
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()
}
}
これをREPLに貼り付けてから、次のように記述します。
scala> ParCollection
そしてREPLがハングします。