我相信我有這個問題的解決方案,我實現了它在全面測試後的應用程序和它的作品。
withPool closure作爲第一個參數傳入創建的池(a jsr166y.ForkJoinPool)。我可以抓住這一點,保存它關閉在一個變量(currentPool),要由主線程以後使用,就像這樣:
GParsPool.withPool { pool ->
currentPool = pool
當一個異常被拋出,並返回到主線程對於處理,我可以把它等到一切都完了,像這樣的東西:
} catch (Exception exc) {
if (currentPool) {
while (!currentPool.isQuiescent()) {
Thread.sleep(100)
println 'waiting for threads to finish'
}
}
println 'all done'
}
的isQuiescent()似乎是要確保有沒有做更多的工作,以安全的方式。
請注意,在測試過程中,我還發現異常似乎並不像我原先想象的那樣終止循環的執行。如果我有一個500的列表,並且做了eachParallel,他們都會跑,不管第一個是否有錯誤。所以我必須通過在並行循環的異常處理程序中使用currentPool.shutdownNow()來終止循環。另請參見:GPars - proper way to terminate a parallel collection early
下面是實際的解決方案的完整簡化表示:
void example() {
jsr166y.ForkJoinPool currentPool
AtomicInteger threadCounter = new AtomicInteger(0)
AtomicInteger threadCounterEnd = new AtomicInteger(0)
AtomicReference<Exception> realException = new AtomicReference<Exception>()
try {
GParsPool.withPool { pool ->
currentPool = pool
(1..500).eachParallel {
try {
if (threadCounter.incrementAndGet() == 1) {
throw new RuntimeException('planet blew up!')
}
if (realException.get() != null) {
// We had an exception already in this eachParallel - quit early
return
}
// Do some long work
Integer counter=0
(1..1000000).each() {counter++}
// Flag if we went all the way through
threadCounterEnd.incrementAndGet()
} catch (Exception exc) {
realException.compareAndSet(null, exc)
pool.shutdownNow()
throw realException
}
}
}
} catch (Exception exc) {
// If we used pool.shutdownNow(), we need to look at the real exception.
// This is needed because pool.shutdownNow() sometimes generates a CancellationException
// which can cover up the real exception that caused us to do a shutdownNow().
if (realException.get()) {
exc = realException.get()
}
if (currentPool) {
while (!currentPool.isQuiescent()) {
Thread.sleep(100)
println 'waiting for threads to finish'
}
}
// Do further exception handling here...
exc.printStackTrace()
}
}
回到我前面的例子,如果我拋出異常一日一次通過一個4核的機器上,有大約5個線程排隊。 shutdownNow()會在大約20個左右的線程通過後停止工作,所以在頂端附近進行「退出提前」檢查可以幫助那些20個或更多的線程儘快退出。
只是在這裏發佈它以防萬一它幫助別人,作爲對我在這裏得到的所有幫助的回報。謝謝!
在我的示例中,結果將包含傳遞線程的整數,以及引發異常的字符串。所有線程將完成... –
好的,我看到斷開連接的位置。假設您的集合中有1,000個項目要迭代。如果拋出一個異常,通常會發生的事情是組被中斷 - 它會停止觸發線程,這是我想要的,並且控制權返回到主線程。所以不是每個線程都會被解僱。但是,在主線程中,仍然有線程在異常之前啓動,但尚未完成清理。那有意義嗎? – user1373467
現在,您的建議確實給了我一個想法 - 我可以保留多少實際被解僱並跟蹤完成的數量。我只是希望更簡單一些。但我很欣賞它,它是有用的+1 – user1373467