我如何知道 ExecutorService 中的所有线程何时完成?

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

我知道 shutdown()awaitTermination() 存在。问题是池中的可运行对象需要能够向其添加未知数量(不能使用倒计时锁存器)的其他可运行对象,如果我调用 shutdown() 那些任务将被拒绝。我怎么知道他们什么时候完成?

使用可能对您有帮助的 Future rather than with Runnable. There's this Future#isDone 方法。

如果 Callable 对 return 没有任何意义,请使用 Callable<Void>Future<Void>

如果您可以使用 Guava Futures,您可以使用 Futures.allAsListFutures.successfulAsList。这允许您将从 ExecutorService 返回的多个 Future 实例包装到一个 Future 中,然后您可以使用 isDone() 检查它是否完成(或者只是 get(),就此而言,如果你想阻塞直到完成)。

与其将 Runnable 任务提交给 Executor,不如使用 ForkJoinTask/ForkJoinPoolForkJoinTaskForkJoinPool 中运行,可以生成任意数量的(子)任务并等待它们完成,而不会实际阻塞当前线程。 A ForkJoinTask 在其所有子任务完成后完成,因此当初始(根)ForkJoinTask 完成时,整个计算完成。

详情见Oracle - The Java™ Tutorials - Fork/Join

因为你所有的任务都是没有结果的(Runnable),你应该继承RecursiveAction(它本身就是ForkJoinTask的子类)。实现方法 compute(),并通过调用 invoke(subtask)invokeAll(subtask1, subtask2, ...)subtask.fork() 后跟 subtask.join().[=32= 来生成任意数量的新任务]

整个计算执行如下:

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

不幸的是 Fork/Join 的优点有一些局限性,例如:

(...) 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. (...)

有关详细信息,请参阅 API docs of ForkJoinTask