並列コレクションを終了する最良の方法は何ですか (スレッドの 1 つによってスローされた例外、またはユーザーによって開始された割り込みの場合)?
どちらの場合でも、簡単にフラグを設定して、ループの先頭でチェックすることができました。しかし、コレクションに 10,000 個のアイテムがある場合は、それらを ForkJoinPool にフィードするものは何でも、それらのフィードを停止するように伝えたいと思います。すでに開始されている 5 つまたは 20 ほどのアイテムを終了させますが、それ以上開始しないでください。
これは、私が何を意味するかを確認するためにプラグインできるサンプルです。スレッドの 1 つによる例外のスローをシミュレートすると、スレッド カウントの最初の出力 (「A:」メッセージで) が非常に小さい (5 程度) ことが多いため、コレクションが処理を停止したように見えます。ただし、カウントを GParsPool.withPool の外 (「B:」) に出力すると、それらが実際に実行され続けていることがわかります (常にすべて 100)。
void doIt() {
AtomicInteger threadCounter = new AtomicInteger(0)
AtomicInteger threadCounterEnd = new AtomicInteger(0)
try {
GParsPool.withPool { pool ->
try {
(1..100).eachParallel {
try {
if (threadCounter.incrementAndGet() == 1) {
throw new RuntimeException('planet blew up!')
}
// Do some long work
Integer counter=0
(1..1000000).each() {counter++}
// Flag if we went all the way through
threadCounterEnd.incrementAndGet()
} catch (Exception exc) {
//pool.shutdownNow()
throw new RuntimeException(exc)
}
}
} catch (Exception exc) {
println 'caught exception'
//pool.shutdownNow()
println "A: threads launched was ${threadCounter}, ended was ${threadCounterEnd}"
throw new RuntimeException(exc)
}
}
} catch (Exception exc) {
exc.printStackTrace()
}
println "B: threads launched was ${threadCounter}, ended was ${threadCounterEnd}"
}
eachParallel 内で pool.shutdown() を使用しても、影響はありません。pool.shutdownNow() を使用すると、希望どおりに処理が終了しますが、CancellationException がスローされ、必要な実際の例外がわかりにくくなります。後でアクセスできるように、「実際の」例外を変数に保存することもできますが、並列コレクションに完全に停止するように指示するより良い方法がないかどうか疑問に思う必要があります。