2015-04-04 99 views
1

我知道shutdown()awaitTermination()存在。問題在於池中的runnables需要能夠向其添加一個未知數(不能使用倒數計時器)的其他runnables,如果我調用shutdown(),這些任務將被拒絕。我如何知道他們何時完成?如何知道ExecutorService中的所有線程何時完成?

+0

當一個任務('Runnable')T產生另外n個任務時,你會說這個任務T在完成所有這些任務後完成嗎?那麼任務T和它的子任務之間是否存在(概念上的)依賴關係? – isnot2bad 2015-04-04 22:05:25

+0

對。我遺漏了我正在使用'newFixedThreadPool',其中最大運行線程數是處理器數量。一旦有人可以運行,其他人就不會再有任何工作要做。如果它等到它產生的runnables結束,它就會坐在那裏什麼都不做,並且由於線程數量的限制,程序永遠不會結束。 – user2980766 2015-04-04 22:51:18

+0

因此,您應該使用'ForkJoinTask'。 – isnot2bad 2015-04-04 23:36:45

回答

0

而不是提交Runnable任務到Executor,而應該使用ForkJoinTask/ForkJoinPool來代替。 A ForkJoinTaskForkJoinPool內運行,可以產生任意數量的(子)任務並等待它們完成,而不會實際阻塞當前線程。 A ForkJoinTask在其所有子任務完成時完成,因此當初始(根)ForkJoinTask完成時,完成整個計算。

查看Oracle - The Java™ Tutorials - Fork/Join瞭解詳情。由於你所有的任務都是沒有結果的(Runnable),你應該繼承RecursiveAction(它本身就是ForkJoinTask的一個子類)。執行方法compute(),並通過調用invoke(subtask),invokeAll(subtask1, subtask2, ...)subtask.fork(),然後subtask.join()產生任意數量的新任務。

整個計算是爲執行如下:

MyRecursiveAction task = new MyRecursiveAction(params); 
ForkJoinPool pool = new ForkJoinPool(numberOfThreads); 
pool.invoke(task); // will block until task is done 

Unfortunatley的優點叉/加入有一定的侷限性,例如:

(...)計算中應理想地避免同步方法或除了加入 其他任務或使用同步器(例如發佈 的相位器)以與叉/加入調度協作之外,其他阻塞同步應最小化。可細分的任務 也不會執行阻塞I/O,理想情況下應該訪問完全獨立於其他正在運行的任務訪問的變量。通過不允許檢查異常 (例如拋出IOException)來寬鬆地執行這些指導原則。 (...)

欲瞭解更多詳情,請參閱API docs of ForkJoinTask

+0

這種方式在答案中發揮最大作用。謝謝。 – user2980766 2015-04-07 21:10:20

1

使用Future而不是Runnable。有這個Future#isDone方法可以幫助你。

如果您沒有任何有意義的內容從Callable返回,請使用Callable<Void>Future<Void>

0

如果您能夠使用Guava Futures,您可以使用Futures.allAsListFutures.successfulAsList。這使您可以將從ExecutorService收到的Future個實例包裝爲一個Future,然後您可以使用isDone()(或者只是get(),如果要阻止直到完成)。

相關問題