0

並列コレクションを終了する最良の方法は何ですか (スレッドの 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 がスローされ、必要な実際の例外がわかりにくくなります。後でアクセスできるように、「実際の」例外を変数に保存することもできますが、並列コレクションに完全に停止するように指示するより良い方法がないかどうか疑問に思う必要があります。

4

1 に答える 1

2

そのようなメカニズムATMはありません。プールは、タスクと他の潜在的な計算のタスクを区別できないため、スレッドによるタスクキューの読み取りを停止するメカニズムはありません。スレッドプールの唯一のユーザーであることがわかっている場合は、提案どおりにshutdownNow()を使用できます(前述の結果を伴います)。

他のオプションもご存知だと思いますが、タスクの例外を直接適切にキャッチし、共有アトミックフラグを設定して、他のタスクにすぐに終了するように指示することです。

于 2012-12-13T10:38:42.467 に答える