How do I know when all threads in a ExecutorService are finished?

人盡茶涼 提交于 2021-02-10 14:24:48

问题


I know that shutdown() and awaitTermination() exist. The problem is that the runnables in the pool need to be able to add an unknown number (can't use a countdownlatch) of other runnables to it and if I call shutdown() those tasks will be rejected. How can I know when they're done?


回答1:


Instead of submitting Runnable tasks to an Executor, you should rather use ForkJoinTask/ForkJoinPool instead. A ForkJoinTask runs inside a ForkJoinPool and can spawn an arbitrary number of (sub)tasks and wait for them to complete, without actually blocking the current thread. A ForkJoinTask is complete when all of its sub-tasks are done, so the entire computation is done, when the initial (root) ForkJoinTask is complete.

See Oracle - The Java™ Tutorials - Fork/Join for details.

As all of your tasks are resultless (Runnable), you should subclass RecursiveAction (which is itself a subclass of ForkJoinTask). Implement the method compute(), and spawn an arbitrary number of new tasks there by either calling invoke(subtask), invokeAll(subtask1, subtask2, ...) or subtask.fork() followed by subtask.join().

The entire computation is executed as follows:

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

Unfortunatley the advantages of Fork/Join have some limitations, e.g.:

(...) Computations should ideally avoid synchronized methods or blocks, and should minimize other blocking synchronization apart from joining other tasks or using synchronizers such as Phasers that are advertised to cooperate with fork/join scheduling. Subdividable tasks should also not perform blocking I/O, and should ideally access variables that are completely independent of those accessed by other running tasks. These guidelines are loosely enforced by not permitting checked exceptions such as IOExceptions to be thrown. (...)

For more detail see API docs of ForkJoinTask.




回答2:


Work with Future rather than with Runnable. There's this Future#isDone method that may help you.

In case you don't have anything meaningful to return from the Callable, use Callable<Void> and Future<Void>.




回答3:


If you are able to use Guava Futures, you can use Futures.allAsList or Futures.successfulAsList. This allows you to wrap a number of Future instances that you got back from the ExecutorService into a single Future which you can then check to see if it is finished using isDone() (or just get(), for that matter, if you want to block until completion).



来源:https://stackoverflow.com/questions/29450892/how-do-i-know-when-all-threads-in-a-executorservice-are-finished

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!