问题
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